Skip to content

Commit

Permalink
Support linked resources
Browse files Browse the repository at this point in the history
Fix #1364
  • Loading branch information
laeubi committed Feb 8, 2024
1 parent c3dd65e commit eb1f45e
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
if (eclipseProjectValue.isEmpty() || !eclipseProjectValue.get().hasNature(ApiPlugin.NATURE_ID)) {
return;
}

EclipseProject eclipseProject = eclipseProjectValue.get();
if (supportedPackagingTypes.contains(project.getPackaging())) {
Log log = getLog();
if (skipIfReplaced && wasReplaced()) {
Expand Down Expand Up @@ -179,14 +179,15 @@ public void execute() throws MojoExecutionException, MojoFailureException {
}
ApiAnalysisResult analysisResult;
if (parallel) {
analysisResult = performAnalysis(baselineBundles, dependencyBundles, eclipseFramework);
analysisResult = performAnalysis(baselineBundles, dependencyBundles, eclipseFramework, eclipseProject);
} else {
synchronized (ApiAnalysisMojo.class) {
// due to
// https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues/3885#note_1266412 we
// can not execute more than one analysis without excessive memory consumption
// unless this is fixed it is safer to only run one analysis at a time
analysisResult = performAnalysis(baselineBundles, dependencyBundles, eclipseFramework);
analysisResult = performAnalysis(baselineBundles, dependencyBundles, eclipseFramework,
eclipseProject);
}
}
log.info("API Analysis finished in " + time(start) + ".");
Expand Down Expand Up @@ -253,10 +254,11 @@ public void execute() throws MojoExecutionException, MojoFailureException {
}

private ApiAnalysisResult performAnalysis(Collection<Path> baselineBundles, Collection<Path> dependencyBundles,
EclipseFramework eclipseFramework) throws MojoExecutionException {
EclipseFramework eclipseFramework, EclipseProject eclipseProject) throws MojoExecutionException {
try {
ApiAnalysis analysis = new ApiAnalysis(baselineBundles, dependencyBundles, project.getName(),
fileToPath(apiFilter), fileToPath(apiPreferences), fileToPath(project.getBasedir()), debug,
eclipseProject.getFile(fileToPath(apiFilter)), eclipseProject.getFile(fileToPath(apiPreferences)),
fileToPath(project.getBasedir()), debug,
fileToPath(project.getArtifact().getFile()),
stringToPath(project.getBuild().getOutputDirectory()));
return eclipseFramework.execute(analysis);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,18 +725,22 @@ protected CompilerConfiguration getCompilerConfiguration(List<String> compileSou
CompilerConfiguration compilerConfiguration = super.getCompilerConfiguration(compileSourceRoots,
compileSourceExcludes);
if (useProjectSettings) {
String prefsFilePath = project.getBasedir() + File.separator + PREFS_FILE_PATH;
if (!new File(prefsFilePath).exists()) {
getLog().debug("Parameter 'useProjectSettings' is set to true, but preferences file '" + prefsFilePath
+ "' could not be found");
} else {
Path prefsFilePath = tychoProjectManager.getEclipseProject(project)
.map(eclipse -> eclipse.getFile(PREFS_FILE_PATH))
.orElseGet(() -> new File(project.getBasedir(), PREFS_FILE_PATH).toPath());

if (Files.isRegularFile(prefsFilePath)) {
// make sure that "-properties" is the first custom argument, otherwise it's not possible to override
// any project setting on the command line because the last argument wins.
List<Entry<String, String>> copy = new ArrayList<>(
compilerConfiguration.getCustomCompilerArgumentsEntries());
compilerConfiguration.getCustomCompilerArgumentsEntries().clear();
addCompilerCustomArgument(compilerConfiguration, "-properties", prefsFilePath);
addCompilerCustomArgument(compilerConfiguration, "-properties",
prefsFilePath.toAbsolutePath().toString());
compilerConfiguration.getCustomCompilerArgumentsEntries().addAll(copy);
} else {
getLog().debug("Parameter 'useProjectSettings' is set to true, but preferences file '" + prefsFilePath
+ "' could not be found");
}
}
compilerConfiguration.setTargetVersion(getTargetLevel());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;

/**
* represents information gathered from an "eclipse project" usually stored in a file named
Expand All @@ -33,4 +34,22 @@ public interface EclipseProject {
static EclipseProject parse(Path projectFile) throws IOException {
return ProjectParser.parse(projectFile);
}

/**
* Resolves a path according to the project, this will resolve linked resources
*
* @param path
* @return the resolved path
*/
Path getFile(Path path);

/**
* Resolves a path according to the project, this will resolve linked resources
*
* @param path
* @return the resolved path
*/
Path getFile(String path);

Collection<ProjectVariable> getVariables();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Expand All @@ -31,6 +42,8 @@

class ProjectParser {

private static final Pattern PARENT_PROJECT_PATTERN = Pattern.compile("PARENT-(\\d+)-PROJECT_LOC");

public static EclipseProject parse(Path path) throws IOException {
try (InputStream stream = Files.newInputStream(path)) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Expand Down Expand Up @@ -58,6 +71,15 @@ public static EclipseProject parse(Path path) throws IOException {
for (int i = 0; i < length; i++) {
natureSet.add(natureNodes.item(i).getTextContent());
}
NodeList variableNodes = root.getElementsByTagName("variable");
List<ProjectVariable> variables = IntStream.range(0, variableNodes.getLength())
.mapToObj(i -> variableNodes.item(i)).map(Element.class::cast).map(e -> parseVariable(e))
.filter(Objects::nonNull).toList();
NodeList linkNodes = root.getElementsByTagName("link");
Map<Path, LinkDescription> links = IntStream.range(0, linkNodes.getLength())
.mapToObj(i -> linkNodes.item(i)).map(Element.class::cast).map(e -> parseLink(e))
.filter(Objects::nonNull).collect(Collectors.toMap(LinkDescription::name, Function.identity()));

return new EclipseProject() {

@Override
Expand Down Expand Up @@ -100,10 +122,128 @@ public String getComment() {
}
return comment;
}

@Override
public Path getFile(Path path) {
if (path == null) {
return null;
}
if (!path.isAbsolute()) {
path = location.resolve(path);
}
if (Files.isRegularFile(path)) {
//if the file is already there we don't need to bother any links
return path;
}
Path relative = location.relativize(path);
for (Entry<Path, LinkDescription> entry : links.entrySet()) {
Path linkPath = entry.getKey();
if (relative.startsWith(linkPath)) {
LinkDescription link = entry.getValue();
if (link.type() == LinkDescription.FILE) {
//the path must actually match each others as it is a file!
if (linkPath.startsWith(relative)) {
Path resolvedPath = resolvePath(link.locationURI());
return location.resolve(resolvedPath).normalize();
}
} else if (link.type() == LinkDescription.FOLDER) {
Path linkRelative = linkPath.relativize(relative);
Path resolvedPath = resolvePath(link.locationURI());
if (resolvedPath != null) {
return location.resolve(resolvedPath).resolve(linkRelative).normalize();
}
}
}
}
return path;
}

@Override
public Path getFile(String path) {
return getFile(location.resolve(path));
}

@Override
public Collection<ProjectVariable> getVariables() {
return variables;
}
};
} catch (SAXException | ParserConfigurationException e) {
throw new IOException("parsing failed", e);
}
}

private static Path resolvePath(URI uri) {
String schemeSpecificPart = uri.getSchemeSpecificPart();
if (schemeSpecificPart != null) {
Path path = Path.of(schemeSpecificPart);
int count = path.getNameCount();
if (count > 0) {
//only the first path is allowed to be a variable...
Path first = path.getName(0);
String name = first.toString();
Matcher parentMatcher = PARENT_PROJECT_PATTERN.matcher(name);
if (parentMatcher.matches()) {
Path resolvedPath = Path.of("..");
int p = Integer.parseInt(parentMatcher.group(1));
for (int i = 1; i < p; i++) {
resolvedPath = resolvedPath.resolve("..");
}
for (int i = 1; i < count; i++) {
resolvedPath = resolvedPath.resolve(path.getName(i));
}
return resolvedPath;
}
return path;
}
}
return null;
}

private static ProjectVariable parseVariable(Element element) {
try {
String name = element.getElementsByTagName("name").item(0).getTextContent();
String value = element.getElementsByTagName("value").item(0).getTextContent();
return new ProjectVariable(name, value);
} catch (RuntimeException e) {
//something is wrong here...
return null;
}
}

private static LinkDescription parseLink(Element element) {
try {
String name = element.getElementsByTagName("name").item(0).getTextContent();
String type = element.getElementsByTagName("type").item(0).getTextContent();
String locationURI = element.getElementsByTagName("locationURI").item(0).getTextContent();
return new LinkDescription(Path.of(name), Integer.parseInt(type), URI.create(locationURI));
} catch (RuntimeException e) {
//something is wrong here...
return null;
}
}

static final record LinkDescription(Path name, int type, URI locationURI) {
/**
* Type constant (bit mask value 1) which identifies file resources.
*/
static final int FILE = 0x1;

/**
* Type constant (bit mask value 2) which identifies folder resources.
*/
static final int FOLDER = 0x2;

/**
* Type constant (bit mask value 4) which identifies project resources.
*/
static final int PROJECT = 0x4;

/**
* Type constant (bit mask value 8) which identifies the root resource.
*/
static final int ROOT = 0x8;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.eclipse.tycho.model.project;

public record ProjectVariable(String name, String value) {

}

0 comments on commit eb1f45e

Please sign in to comment.