From 74904265e91c401d947f509cb5d5a390f025564a Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Sun, 5 May 2024 16:06:19 +0200 Subject: [PATCH] Resolve classpath entries against project base directory #3818 When using a linked .classpath file, the path entries within that file are resolved against the directory containing the .classpath file instead of the project base directory into which the .classpath file is linked. With this change, the paths within a .classpath file are resolved against a passed EclipseProject. An existing regression test for linked .classpath files is enhanced to not contain all linked resources in the same folder (thus hiding the bug of using the folder containing the linked .classpath file for resolving classpath entry paths). Fixes https://github.com/eclipse-tycho/tycho/issues/3818 --- .../tycho/core/osgitools/ClasspathReader.java | 14 +++++-- .../junit5-with-linked-resources/.project | 15 +++---- .../linkedclasspath}/.classpath | 0 .../src_test/bundle/test/AdderTest.java | 0 .../src_test/bundle/test/SubtractorTest.java | 0 .../compiler/CompilerClasspathEntryTest.java | 1 + .../model/classpath/ClasspathParser.java | 39 ++++++++++++------- 7 files changed, 41 insertions(+), 28 deletions(-) rename tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/{linkedresources => testresources/linkedclasspath}/.classpath (100%) rename tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/{linkedresources => testresources/linkedtestsources}/src_test/bundle/test/AdderTest.java (100%) rename tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/{linkedresources => testresources/linkedtestsources}/src_test/bundle/test/SubtractorTest.java (100%) diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/ClasspathReader.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/ClasspathReader.java index 598d326aa6..484b4cf3ab 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/ClasspathReader.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/ClasspathReader.java @@ -18,6 +18,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import org.codehaus.plexus.component.annotations.Component; @@ -30,6 +31,7 @@ import org.eclipse.tycho.model.classpath.ClasspathParser; import org.eclipse.tycho.model.classpath.JUnitBundle; import org.eclipse.tycho.model.classpath.ProjectClasspathEntry; +import org.eclipse.tycho.model.project.EclipseProject; @Component(role = ClasspathReader.class) public class ClasspathReader implements Disposable { @@ -48,14 +50,18 @@ public void dispose() { } public Collection parse(File basedir) throws IOException { - - Path resolvedClasspath = projectManager.getEclipseProject(basedir) - .map(project -> project.getFile(ClasspathParser.CLASSPATH_FILENAME)) + Optional eclipseProject = projectManager.getEclipseProject(basedir); + Path resolvedClasspath = eclipseProject.map(project -> project.getFile(ClasspathParser.CLASSPATH_FILENAME)) .orElse(basedir.toPath().resolve(ClasspathParser.CLASSPATH_FILENAME)); return cache.computeIfAbsent(resolvedClasspath.normalize().toString(), f -> { + File resolvedClasspathFile = resolvedClasspath.toFile(); try { - return ClasspathParser.parse(resolvedClasspath.toFile()); + if (eclipseProject.isPresent()) { + return ClasspathParser.parse(resolvedClasspathFile, eclipseProject.get()); + } else { + return ClasspathParser.parse(resolvedClasspathFile); + } } catch (IOException e) { logger.warn("Can't read classpath from " + basedir); return Collections.emptyList(); diff --git a/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/.project b/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/.project index 235a102ae2..92875975a8 100644 --- a/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/.project +++ b/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/.project @@ -32,23 +32,18 @@ org.eclipse.jdt.core.javanature - + .classpath 1 - PROJECT_LOC/linkedresources/.classpath + PARENT-1-PROJECT_LOC/junit5-with-linked-resources/testresources/linkedclasspath/.classpath - + src_test 2 - VARIABLE_SELFREF_VIA_PARENT/linkedresources/src_test/ + PROJECT_LOC/testresources/linkedtestsources/src_test/ - - - VARIABLE_SELFREF_VIA_PARENT - $%7BPARENT-1-PROJECT_LOC%7D/junit5-with-linked-files - - + diff --git a/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/linkedresources/.classpath b/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/testresources/linkedclasspath/.classpath similarity index 100% rename from tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/linkedresources/.classpath rename to tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/testresources/linkedclasspath/.classpath diff --git a/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/linkedresources/src_test/bundle/test/AdderTest.java b/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/testresources/linkedtestsources/src_test/bundle/test/AdderTest.java similarity index 100% rename from tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/linkedresources/src_test/bundle/test/AdderTest.java rename to tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/testresources/linkedtestsources/src_test/bundle/test/AdderTest.java diff --git a/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/linkedresources/src_test/bundle/test/SubtractorTest.java b/tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/testresources/linkedtestsources/src_test/bundle/test/SubtractorTest.java similarity index 100% rename from tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/linkedresources/src_test/bundle/test/SubtractorTest.java rename to tycho-its/projects/compiler.junitcontainer/junit5-with-linked-resources/testresources/linkedtestsources/src_test/bundle/test/SubtractorTest.java diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/compiler/CompilerClasspathEntryTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/compiler/CompilerClasspathEntryTest.java index aeafe19c79..757cb1718b 100644 --- a/tycho-its/src/test/java/org/eclipse/tycho/test/compiler/CompilerClasspathEntryTest.java +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/compiler/CompilerClasspathEntryTest.java @@ -42,6 +42,7 @@ public void testJUnit5ContainerWithLinkedResources() throws Exception { Verifier verifier = getVerifier("compiler.junitcontainer/junit5-with-linked-resources", false, true); verifier.executeGoal("test"); verifier.verifyErrorFreeLog(); + verifier.verifyTextInLog("Compiling 2 source files"); verifier.verifyTextInLog("-- in bundle.test.AdderTest"); verifier.verifyTextInLog("-- in bundle.test.SubtractorTest"); verifier.verifyTextInLog("Tests run: 5, Failures: 0, Errors: 0, Skipped: 0"); diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathParser.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathParser.java index d435c3d0a0..01a2459bcb 100644 --- a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathParser.java +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathParser.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -29,6 +30,7 @@ import javax.xml.parsers.ParserConfigurationException; import org.eclipse.tycho.model.classpath.ContainerAccessRule.Kind; +import org.eclipse.tycho.model.project.EclipseProject; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -38,7 +40,19 @@ public class ClasspathParser { public static final String CLASSPATH_FILENAME = ".classpath"; - public static Collection parse(File file) throws IOException { + public static Collection parse(File classpathFile, EclipseProject project) + throws IOException { + Function pathInProjectResolver = path -> project.getFile(path).normalize().toFile(); + return parse(classpathFile, pathInProjectResolver); + } + + public static Collection parse(File classpathFile) throws IOException { + Function pathInProjectResolver = path -> new File(classpathFile.getParent(), path); + return parse(classpathFile, pathInProjectResolver); + } + + private static Collection parse(File file, Function pathInProjectResolver) + throws IOException { if (!file.isFile()) { return Collections.emptyList(); } @@ -50,14 +64,13 @@ public static Collection parse(File file) throws IOExcept NodeList classpathentries = doc.getDocumentElement().getElementsByTagName("classpathentry"); int length = classpathentries.getLength(); List list = new ArrayList<>(); - String defaultOutput = "bin"; + File defaultOutput = pathInProjectResolver.apply("bin"); for (int i = 0; i < length; i++) { Element classpathentry = (Element) classpathentries.item(i); String kind = classpathentry.getAttribute("kind"); if ("output".equals(kind)) { - defaultOutput = classpathentry.getAttribute("path"); - list.add( - new JDTOuput(new File(file.getParentFile(), defaultOutput), getAttributes(classpathentry))); + defaultOutput = pathInProjectResolver.apply(classpathentry.getAttribute("path")); + list.add(new JDTOuput(defaultOutput, getAttributes(classpathentry))); } } for (int i = 0; i < length; i++) { @@ -66,13 +79,11 @@ public static Collection parse(File file) throws IOExcept String kind = classpathentry.getAttribute("kind"); if ("src".equals(kind)) { - String path = classpathentry.getAttribute("path"); - String output = classpathentry.getAttribute("output"); - if (output.isBlank()) { - output = defaultOutput; - } - list.add(new JDTSourceFolder(new File(file.getParentFile(), path), - new File(file.getParentFile(), output), attributes)); + File path = pathInProjectResolver.apply(classpathentry.getAttribute("path")); + String outputAttribute = classpathentry.getAttribute("output"); + File output = !outputAttribute.isBlank() ? pathInProjectResolver.apply(outputAttribute) + : defaultOutput; + list.add(new JDTSourceFolder(path, output, attributes)); } else if ("con".equals(kind)) { String path = classpathentry.getAttribute("path"); List accessRules = parseAccessRules(classpathentry); @@ -89,8 +100,8 @@ public static Collection parse(File file) throws IOExcept list.add(new JDTContainerClasspathEntry(path, attributes, accessRules)); } } else if ("lib".equals(kind)) { - String path = classpathentry.getAttribute("path"); - list.add(new JDTLibraryClasspathEntry(new File(file.getParentFile(), path), attributes)); + File path = pathInProjectResolver.apply(classpathentry.getAttribute("path")); + list.add(new JDTLibraryClasspathEntry(path, attributes)); } else if ("var".equals(kind)) { String path = classpathentry.getAttribute("path"); if (path.startsWith(M2ClasspathVariable.M2_REPO_VARIABLE_PREFIX)) {