Skip to content

Commit

Permalink
Resolve classpath entries against project base directory #3818
Browse files Browse the repository at this point in the history
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 #3818

(cherry picked from commit 7490426)
  • Loading branch information
HeikoKlare committed May 5, 2024
1 parent 6676774 commit a5076d0
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -48,14 +50,18 @@ public void dispose() {
}

public Collection<ProjectClasspathEntry> parse(File basedir) throws IOException {

Path resolvedClasspath = projectManager.getEclipseProject(basedir)
.map(project -> project.getFile(ClasspathParser.CLASSPATH_FILENAME))
Optional<EclipseProject> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,18 @@
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<linkedResources>
<!-- A linked file relative to the location of the project -->
<!-- A linked .classpath file relative to the location of the project's parent -->
<link>
<name>.classpath</name>
<type>1</type>
<locationURI>PROJECT_LOC/linkedresources/.classpath</locationURI>
<locationURI>PARENT-1-PROJECT_LOC/junit5-with-linked-resources/testresources/linkedclasspath/.classpath</locationURI>
</link>
<!-- A linked folder relative to the location of the project's parent and defined in a variable -->
<!-- A linked file relative to the location of the project -->
<link>
<name>src_test</name>
<type>2</type>
<locationURI>VARIABLE_SELFREF_VIA_PARENT/linkedresources/src_test/</locationURI>
<locationURI>PROJECT_LOC/testresources/linkedtestsources/src_test/</locationURI>
</link>
</linkedResources>
<variableList>
<variable>
<name>VARIABLE_SELFREF_VIA_PARENT</name>
<value>$%7BPARENT-1-PROJECT_LOC%7D/junit5-with-linked-files</value>
</variable>
</variableList>
</projectDescription>

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -38,7 +40,19 @@
public class ClasspathParser {
public static final String CLASSPATH_FILENAME = ".classpath";

public static Collection<ProjectClasspathEntry> parse(File file) throws IOException {
public static Collection<ProjectClasspathEntry> parse(File classpathFile, EclipseProject project)
throws IOException {
Function<String, File> pathInProjectResolver = path -> project.getFile(path).normalize().toFile();
return parse(classpathFile, pathInProjectResolver);
}

public static Collection<ProjectClasspathEntry> parse(File classpathFile) throws IOException {
Function<String, File> pathInProjectResolver = path -> new File(classpathFile.getParent(), path);
return parse(classpathFile, pathInProjectResolver);
}

private static Collection<ProjectClasspathEntry> parse(File file, Function<String, File> pathInProjectResolver)
throws IOException {
if (!file.isFile()) {
return Collections.emptyList();
}
Expand All @@ -50,14 +64,13 @@ public static Collection<ProjectClasspathEntry> parse(File file) throws IOExcept
NodeList classpathentries = doc.getDocumentElement().getElementsByTagName("classpathentry");
int length = classpathentries.getLength();
List<ProjectClasspathEntry> 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++) {
Expand All @@ -66,13 +79,11 @@ public static Collection<ProjectClasspathEntry> 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<ContainerAccessRule> accessRules = parseAccessRules(classpathentry);
Expand All @@ -89,8 +100,8 @@ public static Collection<ProjectClasspathEntry> 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)) {
Expand Down

0 comments on commit a5076d0

Please sign in to comment.