View Javadoc

1   /**
2    * Copyright (C) 2008 Atlassian
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.atlassian.theplugin.util;
18  
19  import com.atlassian.theplugin.commons.crucible.api.model.CrucibleFileInfo;
20  import com.atlassian.theplugin.idea.IdeaVersionFacade;
21  import com.atlassian.theplugin.idea.VcsIdeaHelper;
22  import com.intellij.openapi.project.Project;
23  import com.intellij.openapi.vfs.VirtualFile;
24  import com.intellij.psi.PsiFile;
25  import org.apache.commons.io.FilenameUtils;
26  import org.apache.commons.lang.StringUtils;
27  import org.jetbrains.annotations.Nullable;
28  
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Set;
32  
33  public final class CodeNavigationUtil {
34  
35  	private CodeNavigationUtil() {
36  		// this is utility class
37  	}
38  
39  	/**
40  	 * Note: must be run from event dispatch thread or inside read-action only!
41  	 */
42  	@Nullable
43  	public static PsiFile guessMatchingFile(String pathname, PsiFile[] psifiles, VirtualFile baseDir) {
44  		// PL-822 fix
45  		// for making it work if pathname comes from different OS than the file itself
46  		// e.g. Bamboo works on Windows, send pathname and the user has a project opened in IDEA on Linux
47  		pathname = pathname.replace('\\', '/');
48  
49  		PsiFile bestMatch = null;
50  
51  		int difference = 0;
52  
53  		for (PsiFile psiFile : psifiles) {
54  			// we use hard-coded '/' as separator in order to make string comparison platform independent
55  			String absolutePath = psiFile.getVirtualFile().getUrl();
56  			if (absolutePath == null) {
57  				continue;
58  			}
59  
60  			int diff = StringUtils.indexOfDifference(StringUtils.reverse(pathname)
61  					, StringUtils.reverse(absolutePath));
62  			if (diff >= FilenameUtils.getName(absolutePath).length()
63  					&& (diff > difference || absolutePath.equals(pathname))) {
64  				difference = diff;
65  				bestMatch = psiFile;
66  				if (absolutePath.equals(pathname)) {
67  					break;
68  				}
69  			}
70  		}
71  		return bestMatch;
72  	}
73  
74  	/**
75  	 * Get files from the provided collection which absolute path contains provided filePath
76  	 *
77  	 * @param filePath searched file path
78  	 * @param psiFiles collection of files to search for filePath
79  	 * @return collection of files matching provided filePath
80  	 */
81  	static Collection<PsiFile> getMatchingFiles(String filePath, final PsiFile[] psiFiles) {
82  		filePath = filePath.replace('\\', '/');
83  
84  		Collection<PsiFile> match = new ArrayList<PsiFile>();
85  
86  		for (PsiFile psiFile : psiFiles) {
87  			String absolutePath = psiFile.getVirtualFile().getUrl();
88  			absolutePath = absolutePath.replace('\\', '/');
89  			if (absolutePath == null) {
90  				continue;
91  			}
92  
93  			if (absolutePath.endsWith(FilenameUtils.getName(filePath)) && absolutePath.contains(filePath)) {
94  				match.add(psiFile);
95  			}
96  		}
97  		return match;
98  	}
99  
100 	public static CrucibleFileInfo getBestMatchingCrucibleFileInfo(String path, Set<CrucibleFileInfo> files) {
101 		path = path.replace('\\', '/');
102 
103 		CrucibleFileInfo bestMatch = null;
104 		int difference = 0;
105 
106 		for (CrucibleFileInfo file : files) {
107 			String pathname = "";
108 			switch (file.getCommitType()) {
109 				case Added:
110 				case Modified:
111 				case Copied:
112 				case Moved:
113 					pathname = file.getFileDescriptor().getAbsoluteUrl();
114 					break;
115 				case Deleted:
116 					pathname = file.getOldFileDescriptor().getAbsoluteUrl();
117 					break;
118 				default:
119 					pathname = file.getOldFileDescriptor().getAbsoluteUrl();
120 					break;
121 
122 			}
123 			int diff = StringUtils.indexOfDifference(StringUtils.reverse(path)
124 					, StringUtils.reverse(pathname));
125 			if (diff == -1 || (diff >= FilenameUtils.getName(pathname).length()
126 					&& (diff > difference || pathname.equals(path)))) {
127 				difference = diff;
128 				bestMatch = file;
129 				if (pathname.equals(path)) {
130 					break;
131 				}
132 			}
133 		}
134 		if (difference < StringUtils.reverse(path).indexOf('/')) {
135 			return null;
136 		}
137 		return bestMatch;
138 	}
139 
140 	/**
141 	 * Note: must be run from event dispatch thread or inside read-action only!
142 	 */
143 	@Nullable
144 	public static PsiFile guessCorrespondingPsiFile(final Project project, final String filepath) {
145 		final PsiFile[] psifiles = IdeaVersionFacade.getInstance().getFiles(FilenameUtils.getName(filepath), project);
146 		return CodeNavigationUtil.guessMatchingFile(filepath, psifiles, project.getBaseDir());
147 	}
148 
149 	/**
150 	 * Note: must be run from event dispatch thread or inside read-action only!
151 	 *
152 	 * @param project  project
153 	 * @param filePath filePath
154 	 * @return collection of matching PsiFiles
155 	 */
156 	@Nullable
157 	public static Collection<PsiFile> findPsiFiles(final Project project, final String filePath) {
158 		// find files (do not care about path - IDEA7 compatibility)
159 		final PsiFile[] psifiles = IdeaVersionFacade.getInstance().getFiles(FilenameUtils.getName(filePath), project);
160 
161 		return CodeNavigationUtil.getMatchingFiles(filePath, psifiles);
162 	}
163 
164 	/**
165 	 * In the collection of provided files looks for those which match vcs url
166 	 *
167 	 * @param psiFiles collection of files to search
168 	 * @param vcsUrl   searched vcs url
169 	 * @param project  project
170 	 * @return collection of found PsiFiles
171 	 */
172 	public static Collection<PsiFile> findPsiFilesWithVcsUrl(final Collection<PsiFile> psiFiles, final String vcsUrl,
173 			final Project project) {
174 		Collection<PsiFile> retFiles = new ArrayList<PsiFile>();
175 		if (psiFiles != null && vcsUrl != null && project != null) {
176 			for (PsiFile psiFile : psiFiles) {
177 				String repositoryUrl = VcsIdeaHelper.getRepositoryRootUrlForFile(project, psiFile.getVirtualFile());
178 				if (repositoryUrl.equals(vcsUrl)) {
179 					retFiles.add(psiFile);
180 				}
181 			}
182 		}
183 
184 		return retFiles;
185 	}
186 }