eclipse: project name should be found in .project (IDEA-52070 )
[fedora-idea.git] / plugins / eclipse / src / org / jetbrains / idea / eclipse / conversion / EclipseClasspathReader.java
blob815624003b79b05ab59c9a8414a82366fe8406d2
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * User: anna
19 * Date: 11-Nov-2008
21 package org.jetbrains.idea.eclipse.conversion;
23 import com.intellij.openapi.components.PathMacroManager;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.openapi.module.ModuleManager;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.projectRoots.ProjectJdkTable;
28 import com.intellij.openapi.projectRoots.Sdk;
29 import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
30 import com.intellij.openapi.roots.*;
31 import com.intellij.openapi.roots.libraries.Library;
32 import com.intellij.openapi.roots.libraries.LibraryTable;
33 import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
34 import com.intellij.openapi.util.Comparing;
35 import com.intellij.openapi.util.SystemInfo;
36 import com.intellij.openapi.vfs.JarFileSystem;
37 import com.intellij.openapi.vfs.VfsUtil;
38 import com.intellij.openapi.vfs.VirtualFile;
39 import com.intellij.openapi.vfs.VirtualFileManager;
40 import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
41 import com.intellij.util.ArrayUtil;
42 import org.jdom.Element;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
45 import org.jetbrains.idea.eclipse.EclipseXml;
46 import org.jetbrains.idea.eclipse.IdeaXml;
47 import org.jetbrains.idea.eclipse.config.EclipseModuleManager;
48 import org.jetbrains.idea.eclipse.importWizard.EclipseProjectFinder;
49 import org.jetbrains.idea.eclipse.util.ErrorLog;
51 import java.io.File;
52 import java.io.IOException;
53 import java.util.ArrayList;
54 import java.util.Collection;
55 import java.util.List;
56 import java.util.Set;
58 public class EclipseClasspathReader {
59 private final String myRootPath;
60 private final Project myProject;
61 @Nullable private final List<String> myCurrentRoots;
62 private ContentEntry myContentEntry;
64 public EclipseClasspathReader(final String rootPath, final Project project, @Nullable List<String> currentRoots) {
65 myRootPath = rootPath;
66 myProject = project;
67 myCurrentRoots = currentRoots;
70 public void init(ModifiableRootModel model) {
71 myContentEntry = model.addContentEntry(VfsUtil.pathToUrl(myRootPath));
72 model.inheritSdk();
75 public static void collectVariables(Set<String> usedVariables, Element classpathElement) {
76 for (Object o : classpathElement.getChildren(EclipseXml.CLASSPATHENTRY_TAG)) {
77 final Element element = (Element)o;
78 final String kind = element.getAttributeValue(EclipseXml.KIND_ATTR);
79 if (Comparing.strEqual(kind, EclipseXml.VAR_KIND)) {
80 String path = element.getAttributeValue(EclipseXml.PATH_ATTR);
81 if (path == null) continue;
82 int slash = path.indexOf("/");
83 if (slash > 0) {
84 usedVariables.add(path.substring(0, slash));
86 else {
87 usedVariables.add(path);
91 final String srcPath = element.getAttributeValue(EclipseXml.SOURCEPATH_ATTR);
92 if (srcPath == null) continue;
93 final int varStart = srcPath.startsWith("/") ? 1 : 0;
94 final int slash2 = srcPath.indexOf("/", varStart);
95 if (slash2 > 0) {
96 usedVariables.add(srcPath.substring(varStart, slash2));
98 else {
99 usedVariables.add(srcPath.substring(varStart));
105 public void readClasspath(ModifiableRootModel model,
106 final Collection<String> unknownLibraries,
107 Collection<String> unknownJdks,
108 final Set<String> usedVariables,
109 Set<String> refsToModules,
110 final String testPattern,
111 Element classpathElement) throws IOException, ConversionException {
112 for (OrderEntry orderEntry : model.getOrderEntries()) {
113 if (!(orderEntry instanceof ModuleSourceOrderEntry)) {
114 model.removeOrderEntry(orderEntry);
117 for (Object o : classpathElement.getChildren(EclipseXml.CLASSPATHENTRY_TAG)) {
118 try {
119 readClasspathEntry(model, unknownLibraries, unknownJdks, usedVariables, refsToModules, testPattern, (Element)o);
121 catch (ConversionException e) {
122 ErrorLog.rethrow(ErrorLog.Level.Warning, null, EclipseXml.CLASSPATH_FILE, e);
127 private void readClasspathEntry(ModifiableRootModel rootModel,
128 final Collection<String> unknownLibraries,
129 Collection<String> unknownJdks,
130 final Set<String> usedVariables,
131 Set<String> refsToModules,
132 final String testPattern,
133 Element element) throws ConversionException {
134 String kind = element.getAttributeValue(EclipseXml.KIND_ATTR);
135 if (kind == null) {
136 throw new ConversionException("Missing classpathentry/@kind");
140 String path = element.getAttributeValue(EclipseXml.PATH_ATTR);
141 if (path == null) {
142 throw new ConversionException("Missing classpathentry/@path");
145 final boolean exported = EclipseXml.TRUE_VALUE.equals(element.getAttributeValue(EclipseXml.EXPORTED_ATTR));
147 if (kind.equals(EclipseXml.SRC_KIND)) {
148 if (path.startsWith("/")) {
149 final String moduleName = path.substring(1);
150 refsToModules.add(moduleName);
151 rootModel.addInvalidModuleEntry(moduleName).setExported(exported);
153 else {
154 getContentEntry().addSourceFolder(VfsUtil.pathToUrl(myRootPath + "/" + path), testPattern != null && testPattern.length() > 0 && path.matches(testPattern));
158 else if (kind.equals(EclipseXml.OUTPUT_KIND)) {
159 setupOutput(rootModel, myRootPath + "/" + path);
162 else if (kind.equals(EclipseXml.LIB_KIND)) {
163 final String libName = getPresentableName(path);
164 final Library library = rootModel.getModuleLibraryTable().getModifiableModel().createLibrary(libName);
165 final Library.ModifiableModel modifiableModel = library.getModifiableModel();
167 modifiableModel.addRoot(getUrl(path), OrderRootType.CLASSES);
169 final String sourcePath = element.getAttributeValue(EclipseXml.SOURCEPATH_ATTR);
170 if (sourcePath != null) {
171 modifiableModel.addRoot(getUrl(sourcePath), OrderRootType.SOURCES);
174 final List<String> docPaths = getJavadocAttribute(element);
175 if (docPaths != null) {
176 for (String docPath : docPaths) {
177 modifiableModel.addRoot(docPath, JavadocOrderRootType.getInstance());
181 modifiableModel.commit();
183 setLibraryEntryExported(rootModel, exported, library);
185 else if (kind.equals(EclipseXml.VAR_KIND)) {
186 int slash = path.indexOf("/");
187 if (slash == 0) {
188 throw new ConversionException("Incorrect 'classpathentry/var@path' format");
191 final String libName = getPresentableName(path);
192 final Library library = rootModel.getModuleLibraryTable().getModifiableModel().createLibrary(libName);
193 final Library.ModifiableModel modifiableModel = library.getModifiableModel();
196 final String clsVar;
197 final String clsPath;
198 if (slash > 0) {
199 clsVar = path.substring(0, slash);
200 clsPath = path.substring(slash + 1);
202 else {
203 clsVar = path;
204 clsPath = null;
206 usedVariables.add(clsVar);
208 final String url = getUrl(PathMacroManager.getInstance(rootModel.getModule()).expandPath(getVariableRelatedPath(clsVar, clsPath)));
209 EclipseModuleManager.getInstance(rootModel.getModule()).registerEclipseVariablePath(url, path);
210 modifiableModel.addRoot(url, OrderRootType.CLASSES);
212 final String srcPathAttr = element.getAttributeValue(EclipseXml.SOURCEPATH_ATTR);
213 if (srcPathAttr != null) {
214 final String srcVar;
215 final String srcPath;
216 final int varStart = srcPathAttr.startsWith("/") ? 1 : 0;
218 int slash2 = srcPathAttr.indexOf("/", varStart);
219 if (slash2 > 0) {
220 srcVar = srcPathAttr.substring(varStart, slash2);
221 srcPath = srcPathAttr.substring(slash2 + 1);
223 else {
224 srcVar = srcPathAttr.substring(varStart);
225 srcPath = null;
227 usedVariables.add(srcVar);
228 final String srcUrl = getUrl(PathMacroManager.getInstance(rootModel.getModule()).expandPath(getVariableRelatedPath(srcVar, srcPath)));
229 EclipseModuleManager.getInstance(rootModel.getModule()).registerEclipseSrcVariablePath(srcUrl, srcPathAttr);
230 modifiableModel.addRoot(srcUrl, OrderRootType.SOURCES);
233 final List<String> docPaths = getJavadocAttribute(element);
234 if (docPaths != null) {
235 for (String docPath : docPaths) {
236 modifiableModel.addRoot(docPath, JavadocOrderRootType.getInstance());
240 modifiableModel.commit();
242 setLibraryEntryExported(rootModel, exported, library);
244 else if (kind.equals(EclipseXml.CON_KIND)) {
245 if (path.equals(EclipseXml.ECLIPSE_PLATFORM)) {
246 addNamedLibrary(rootModel, unknownLibraries, exported, IdeaXml.ECLIPSE_LIBRARY, LibraryTablesRegistrar.APPLICATION_LEVEL);
248 else if (path.startsWith(EclipseXml.JRE_CONTAINER)) {
250 final String jdkName = getLastPathComponent(path);
251 if (jdkName == null) {
252 rootModel.inheritSdk();
254 else {
255 final Sdk moduleJdk = ProjectJdkTable.getInstance().findJdk(jdkName);
256 if (moduleJdk != null) {
257 rootModel.setSdk(moduleJdk);
259 else {
260 rootModel.setInvalidSdk(jdkName, IdeaXml.JAVA_SDK_TYPE);
261 unknownJdks.add(jdkName);
264 OrderEntry[] orderEntries = rootModel.getOrderEntries();
265 orderEntries = ArrayUtil.append(orderEntries, orderEntries[0]);
266 rootModel.rearrangeOrderEntries(ArrayUtil.remove(orderEntries, 0));
268 else if (path.startsWith(EclipseXml.USER_LIBRARY)) {
269 addNamedLibrary(rootModel, unknownLibraries, exported, getPresentableName(path), LibraryTablesRegistrar.PROJECT_LEVEL);
271 else if (path.startsWith(EclipseXml.JUNIT_CONTAINER)) {
272 final String junitName = IdeaXml.JUNIT + getPresentableName(path);
273 final Library library = rootModel.getModuleLibraryTable().getModifiableModel().createLibrary(junitName);
274 final Library.ModifiableModel modifiableModel = library.getModifiableModel();
275 modifiableModel.addRoot(getJunitClsUrl(junitName.contains("4")), OrderRootType.CLASSES);
276 modifiableModel.commit();
279 else {
280 throw new ConversionException("Unknown classpathentry/@kind: " + kind);
284 public static void setupOutput(ModifiableRootModel rootModel, final String path) {
285 final CompilerModuleExtension compilerModuleExtension = rootModel.getModuleExtension(CompilerModuleExtension.class);
286 compilerModuleExtension.setCompilerOutputPath(VfsUtil.pathToUrl(path));
287 compilerModuleExtension.inheritCompilerOutputPath(false);
290 private static void setLibraryEntryExported(ModifiableRootModel rootModel, boolean exported, Library library) {
291 for (OrderEntry orderEntry : rootModel.getOrderEntries()) {
292 if (orderEntry instanceof LibraryOrderEntry &&
293 ((LibraryOrderEntry)orderEntry).isModuleLevel() &&
294 Comparing.equal(((LibraryOrderEntry)orderEntry).getLibrary(), library)) {
295 ((LibraryOrderEntry)orderEntry).setExported(exported);
296 break;
301 private void addNamedLibrary(final ModifiableRootModel rootModel,
302 final Collection<String> unknownLibraries,
303 final boolean exported,
304 final String name,
305 final String notFoundLibraryLevel) {
306 Library lib = findLibraryByName(myProject, name);
307 if (lib != null) {
308 rootModel.addLibraryEntry(lib).setExported(exported);
310 else {
311 unknownLibraries.add(name);
312 rootModel.addInvalidLibrary(name, notFoundLibraryLevel).setExported(exported);
316 public static Library findLibraryByName(Project project, String name) {
317 final LibraryTablesRegistrar tablesRegistrar = LibraryTablesRegistrar.getInstance();
318 Library lib = tablesRegistrar.getLibraryTable().getLibraryByName(name);
319 if (lib == null) {
320 lib = tablesRegistrar.getLibraryTable(project).getLibraryByName(name);
322 if (lib == null) {
323 for (LibraryTable table : tablesRegistrar.getCustomLibraryTables()) {
324 lib = table.getLibraryByName(name);
325 if (lib != null) {
326 break;
330 return lib;
333 @NotNull
334 private static String getPresentableName(@NotNull String path) {
335 final String pathComponent = getLastPathComponent(path);
336 return pathComponent != null ? pathComponent : path;
339 @Nullable
340 public static String getLastPathComponent(final String path) {
341 final int idx = path.lastIndexOf('/');
342 return idx < 0 || idx == path.length() - 1 ? null : path.substring(idx + 1);
345 private ContentEntry getContentEntry() {
346 return myContentEntry;
349 private static String getVariableRelatedPath(String var, String path) {
350 return var == null ? null : ("$" + var + "$" + (path == null ? "" : ("/" + path)));
353 private String getUrl(final String path) {
354 String url = null;
355 if (path.startsWith("/")) {
356 final String relativePath = new File(myRootPath).getParent() + "/" + path;
357 final File file = new File(relativePath);
358 if (file.exists()) {
359 url = VfsUtil.pathToUrl(relativePath);
360 } else if (new File(path).exists()) {
361 url = VfsUtil.pathToUrl(path);
363 else {
364 final String rootPath = getRootPath(path);
365 final String relativeToRootPath = getRelativeToRootPath(path);
367 final Module otherModule = ModuleManager.getInstance(myProject).findModuleByName(rootPath);
368 if (otherModule != null) {
369 url = relativeToOtherModule(otherModule, relativeToRootPath);
371 else if (myCurrentRoots != null) {
372 url = relativeToContentRoots(myCurrentRoots, rootPath, relativeToRootPath);
376 if (url == null) {
377 final String absPath = myRootPath + "/" + path;
378 if (new File(absPath).exists()) {
379 url = VfsUtil.pathToUrl(absPath);
381 else {
382 url = VfsUtil.pathToUrl(path);
385 final VirtualFile localFile = VirtualFileManager.getInstance().findFileByUrl(url);
386 if (localFile != null) {
387 final VirtualFile jarFile = JarFileSystem.getInstance().getJarRootForLocalFile(localFile);
388 if (jarFile != null) {
389 url = jarFile.getUrl();
392 return url;
396 * @param path path in format /module_root/relative_path
397 * @return module_root
399 @NotNull
400 private static String getRootPath(String path) {
401 int secondSlIdx = path.indexOf('/', 1);
402 return secondSlIdx > 1 ? path.substring(1, secondSlIdx) : path.substring(1);
406 * @param path path in format /module_root/relative_path
407 * @return relative_path or null if /module_root
409 @Nullable
410 private static String getRelativeToRootPath(String path) {
411 final int secondSlIdx = path.indexOf('/', 1);
412 return secondSlIdx != -1 && secondSlIdx + 1 < path.length() ? path.substring(secondSlIdx + 1) : null;
415 @Nullable
416 private static String relativeToContentRoots(final @NotNull List<String> currentRoots,
417 final @NotNull String rootPath,
418 final @Nullable String relativeToRootPath) {
419 for (String currentRoot : currentRoots) {
420 if (currentRoot.endsWith(rootPath) || Comparing.strEqual(rootPath, EclipseProjectFinder.findProjectName(currentRoot))) { //rootPath = content_root <=> applicable root: abs_path/content_root
421 if (relativeToRootPath == null) {
422 return VfsUtil.pathToUrl(currentRoot);
424 final File relativeToOtherModuleFile = new File(currentRoot, relativeToRootPath);
425 if (relativeToOtherModuleFile.exists()) {
426 return VfsUtil.pathToUrl(relativeToOtherModuleFile.getPath());
430 return null;
433 @Nullable
434 private static String relativeToOtherModule(final @NotNull Module otherModule, final @Nullable String relativeToOtherModule) {
435 final VirtualFile[] contentRoots = ModuleRootManager.getInstance(otherModule).getContentRoots();
436 for (VirtualFile contentRoot : contentRoots) {
437 if (relativeToOtherModule == null) {
438 return contentRoot.getUrl();
440 final File relativeToOtherModuleFile = new File(contentRoot.getPath(), relativeToOtherModule);
441 if (relativeToOtherModuleFile.exists()) {
442 return VfsUtil.pathToUrl(relativeToOtherModuleFile.getPath());
445 return null;
448 @Nullable
449 private List<String> getJavadocAttribute(Element element) {
450 Element attributes = element.getChild("attributes");
451 if (attributes == null) {
452 return null;
454 List<String> result = new ArrayList<String>();
455 for (Object o : attributes.getChildren("attribute")) {
456 if (Comparing.strEqual(((Element)o).getAttributeValue("name"), "javadoc_location")) {
457 Element attribute = (Element)o;
458 String javadocPath = attribute.getAttributeValue("value");
459 if (!SystemInfo.isWindows) {
460 javadocPath = javadocPath.replaceFirst(EclipseXml.FILE_PROTOCOL, EclipseXml.FILE_PROTOCOL + "/");
462 if (javadocPath.startsWith(EclipseXml.FILE_PROTOCOL) &&
463 new File(javadocPath.substring(EclipseXml.FILE_PROTOCOL.length())).exists()) {
464 result.add(VfsUtil.pathToUrl(javadocPath.substring(EclipseXml.FILE_PROTOCOL.length())));
466 else {
468 final String protocol = VirtualFileManager.extractProtocol(javadocPath);
469 if (Comparing.strEqual(protocol, HttpFileSystem.getInstance().getProtocol())) {
470 result.add(javadocPath);
472 else if (javadocPath.startsWith(EclipseXml.JAR_PREFIX)) {
473 final String jarJavadocPath = javadocPath.substring(EclipseXml.JAR_PREFIX.length());
474 if (jarJavadocPath.startsWith(EclipseXml.PLATFORM_PROTOCOL)) {
475 String relativeToPlatform = jarJavadocPath.substring(EclipseXml.PLATFORM_PROTOCOL.length() + "resources".length());
476 result
477 .add(VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, new File(myRootPath).getParent() + "/" + relativeToPlatform));
479 else if (jarJavadocPath.startsWith(EclipseXml.FILE_PROTOCOL)) {
480 result
481 .add(VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, jarJavadocPath.substring(EclipseXml.FILE_PROTOCOL.length())));
483 else {
484 result.add(javadocPath);
490 return result;
493 static String getJunitClsUrl(final boolean version4) {
494 String url = version4 ? JavaSdkUtil.getJunit4JarPath() : JavaSdkUtil.getJunit3JarPath();
495 final VirtualFile localFile = VirtualFileManager.getInstance().findFileByUrl(VfsUtil.pathToUrl(url));
496 if (localFile != null) {
497 final VirtualFile jarFile = JarFileSystem.getInstance().getJarRootForLocalFile(localFile);
498 url = jarFile != null ? jarFile.getUrl() : localFile.getUrl();
500 return url;