Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tycho-4.0.x] Support access rules defined from the classpath #3447

Merged
merged 1 commit into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@
import org.eclipse.tycho.core.osgitools.project.EclipsePluginProject;
import org.eclipse.tycho.core.resolver.shared.PomDependencies;
import org.eclipse.tycho.helper.PluginRealmHelper;
import org.eclipse.tycho.model.classpath.ClasspathContainerEntry;
import org.eclipse.tycho.model.classpath.ContainerAccessRule;
import org.eclipse.tycho.model.classpath.JREClasspathEntry;
import org.eclipse.tycho.model.classpath.M2ClasspathVariable;
import org.eclipse.tycho.model.classpath.PluginDependenciesClasspathContainer;
import org.eclipse.tycho.model.classpath.ProjectClasspathEntry;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
Expand Down Expand Up @@ -570,10 +573,19 @@ protected File getOutputDirectory() {

@Override
public List<String> getClasspathElements() throws MojoExecutionException {
Collection<ProjectClasspathEntry> classpathEntries = getEclipsePluginProject().getClasspathEntries();
final List<String> classpath = new ArrayList<>();
Set<String> seen = new HashSet<>();
Set<String> includedPathes = new HashSet<>();
boolean useAccessRules = JDT_COMPILER_ID.equals(compilerId);
List<ContainerAccessRule> globalRules;
if (useAccessRules) {
globalRules = classpathEntries.stream().filter(PluginDependenciesClasspathContainer.class::isInstance)
.map(PluginDependenciesClasspathContainer.class::cast).map(ClasspathContainerEntry::getAccessRules)
.findFirst().orElse(List.of());
} else {
globalRules = List.of();
}
for (ClasspathEntry cpe : getClasspath()) {
Stream<File> classpathLocations = Stream
.concat(cpe.getLocations().stream(),
Expand All @@ -582,7 +594,7 @@ public List<String> getClasspathElements() throws MojoExecutionException {
.filter(AbstractOsgiCompilerMojo::isValidLocation).distinct();
classpathLocations.forEach(location -> {
String path = location.getAbsolutePath();
String entry = path + toString(cpe.getAccessRules(), useAccessRules);
String entry = path + toString(cpe.getAccessRules(), globalRules, useAccessRules);
if (seen.add(entry)) {
includedPathes.add(path);
classpath.add(entry);
Expand All @@ -593,7 +605,6 @@ public List<String> getClasspathElements() throws MojoExecutionException {
ArtifactRepository repository = session.getLocalRepository();
if (repository != null) {
String basedir = repository.getBasedir();
Collection<ProjectClasspathEntry> classpathEntries = getEclipsePluginProject().getClasspathEntries();
for (ProjectClasspathEntry cpe : classpathEntries) {
if (cpe instanceof M2ClasspathVariable cpv) {
String entry = new File(basedir, cpv.getRepositoryPath()).getAbsolutePath();
Expand Down Expand Up @@ -647,17 +658,33 @@ protected BundleProject getBundleProject() throws MojoExecutionException {
return (BundleProject) projectType;
}

private String toString(Collection<AccessRule> rules, boolean useAccessRules) {
private String toString(Collection<AccessRule> entryRules, List<ContainerAccessRule> containerRules,
boolean useAccessRules) {
if (useAccessRules) {
StringJoiner result = new StringJoiner(RULE_SEPARATOR, "[", "]"); // include all
if (rules != null) {
for (AccessRule rule : rules) {
result.add((rule.isDiscouraged() ? "~" : "+") + rule.getPattern());
if (entryRules != null) {
for (ContainerAccessRule rule : containerRules) {
switch (rule.getKind()) {
case ACCESSIBLE:
result.add("+" + rule.getPattern());
break;
case DISCOURAGED:
result.add("~" + rule.getPattern());
break;
case NON_ACCESSIBLE:
result.add("-" + rule.getPattern());
break;
default:
break;
}
}
if (entryRules != null) {
for (AccessRule rule : entryRules) {
result.add((rule.isDiscouraged() ? "~" : "+") + rule.getPattern());
}
}
result.add(RULE_EXCLUDE_ALL);
} else {
// include everything, not strictly necessary, but lets make this obvious
//result.append("[+**/*]");
return "";
}
return result.toString();
Expand Down Expand Up @@ -734,9 +761,9 @@ protected CompilerConfiguration getCompilerConfiguration(List<String> compileSou
compilerConfiguration.setReleaseVersion(releaseLevel);
}
configureJavaHome(compilerConfiguration);
configureBootclasspathAccessRules(compilerConfiguration);
configureCompilerLog(compilerConfiguration);
Collection<ProjectClasspathEntry> classpathEntries = getEclipsePluginProject().getClasspathEntries();
configureBootclasspathAccessRules(compilerConfiguration, classpathEntries);
configureCompilerLog(compilerConfiguration);
for (ProjectClasspathEntry cpe : classpathEntries) {
if (cpe instanceof JREClasspathEntry jreClasspathEntry) {
if (jreClasspathEntry.isModule()) {
Expand Down Expand Up @@ -789,8 +816,8 @@ private void configureCompilerLog(CompilerConfiguration compilerConfiguration) t
addCompilerCustomArgument(compilerConfiguration, "-log", logPath);
}

private void configureBootclasspathAccessRules(CompilerConfiguration compilerConfiguration)
throws MojoExecutionException {
private void configureBootclasspathAccessRules(CompilerConfiguration compilerConfiguration,
Collection<ProjectClasspathEntry> classpathEntries) throws MojoExecutionException {
List<AccessRule> accessRules = new ArrayList<>();

if (requireJREPackageImports != null) {
Expand All @@ -815,8 +842,11 @@ private void configureBootclasspathAccessRules(CompilerConfiguration compilerCon
.addAll(getBundleProject().getBootClasspathExtraAccessRules(DefaultReactorProject.adapt(project)));
}
if (!accessRules.isEmpty()) {
List<ContainerAccessRule> globalRules = classpathEntries.stream()
.filter(JREClasspathEntry.class::isInstance).map(JREClasspathEntry.class::cast)
.map(ClasspathContainerEntry::getAccessRules).findFirst().orElse(List.of());
addCompilerCustomArgument(compilerConfiguration, "org.osgi.framework.system.packages",
toString(accessRules, true));
toString(accessRules, globalRules, true));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ public String getPattern() {

@Override
public String toString() {
if (isDiscouraged()) {
return getPattern() + " (discouraged)";
}
return getPattern();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*******************************************************************************/
package org.eclipse.tycho.model.classpath;

import java.util.List;

/**
* represents a container classpath entry, this could be for example:
*
Expand All @@ -33,4 +35,10 @@ public interface ClasspathContainerEntry extends ProjectClasspathEntry {
*/
String getContainerPath();

/**
*
* @return the {@link ContainerAccessRule}s defined for this classpathcontainer
*/
List<ContainerAccessRule> getAccessRules();

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.tycho.model.classpath.ContainerAccessRule.Kind;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

Expand Down Expand Up @@ -71,15 +75,18 @@ public static Collection<ProjectClasspathEntry> parse(File basedir) throws IOExc
new File(file.getParentFile(), output), attributes));
} else if ("con".equals(kind)) {
String path = classpathentry.getAttribute("path");
List<ContainerAccessRule> accessRules = parseAccessRules(classpathentry);
if (path.startsWith(JUnitClasspathContainerEntry.JUNIT_CONTAINER_PATH_PREFIX)) {
String junit = path
.substring(JUnitClasspathContainerEntry.JUNIT_CONTAINER_PATH_PREFIX.length());
list.add(new JDTJUnitContainerClasspathEntry(path, junit, attributes));
list.add(new JDTJUnitContainerClasspathEntry(path, junit, attributes, accessRules));
} else if (path.equals(JREClasspathEntry.JRE_CONTAINER_PATH)
|| path.startsWith(JREClasspathEntry.JRE_CONTAINER_PATH_STANDARDVMTYPE_PREFIX)) {
list.add(new JDTJREClasspathEntry(path, attributes));
list.add(new JDTJREClasspathEntry(path, attributes, accessRules));
} else if (path.equals(PluginDependenciesClasspathContainer.PATH)) {
list.add(new RequiredPluginsEntry(path, attributes, accessRules));
} else {
list.add(new JDTContainerClasspathEntry(path, attributes));
list.add(new JDTContainerClasspathEntry(path, attributes, accessRules));
}
} else if ("lib".equals(kind)) {
String path = classpathentry.getAttribute("path");
Expand All @@ -100,6 +107,33 @@ public static Collection<ProjectClasspathEntry> parse(File basedir) throws IOExc
}
}

private static List<ContainerAccessRule> parseAccessRules(Element classpathentry) {
NodeList accessrules = classpathentry.getElementsByTagName("accessrule");
Stream<Node> stream = IntStream.range(0, accessrules.getLength()).mapToObj(i -> accessrules.item(i));
return stream.map(Element.class::cast).map(elem -> {
Kind kind = Kind.parse(elem.getAttribute("kind"));
String pattern = elem.getAttribute("pattern");
ContainerAccessRule r = new ContainerAccessRule() {

@Override
public Kind getKind() {
return kind;
}

@Override
public String getPattern() {
return pattern;
}

@Override
public String toString() {
return pattern + " [" + kind + "]";
}
};
return r;
}).toList();
}

private static Map<String, String> getAttributes(Element parent) {
Map<String, String> map = new HashMap<>();
NodeList attributes = parent.getElementsByTagName("attribute");
Expand All @@ -111,10 +145,21 @@ private static Map<String, String> getAttributes(Element parent) {
return map;
}

private static final class RequiredPluginsEntry extends JDTContainerClasspathEntry
implements PluginDependenciesClasspathContainer {

public RequiredPluginsEntry(String path, Map<String, String> attributes,
List<ContainerAccessRule> accessRules) {
super(path, attributes, accessRules);
}

}

private static final class JDTJREClasspathEntry extends JDTContainerClasspathEntry implements JREClasspathEntry {

public JDTJREClasspathEntry(String path, Map<String, String> attributes) {
super(path, attributes);
public JDTJREClasspathEntry(String path, Map<String, String> attributes,
List<ContainerAccessRule> accessRules) {
super(path, attributes, accessRules);
}

@Override
Expand Down Expand Up @@ -146,8 +191,9 @@ private static class JDTJUnitContainerClasspathEntry extends JDTContainerClasspa

private final String junit;

public JDTJUnitContainerClasspathEntry(String path, String junit, Map<String, String> attributes) {
super(path, attributes);
public JDTJUnitContainerClasspathEntry(String path, String junit, Map<String, String> attributes,
List<ContainerAccessRule> accessRules) {
super(path, attributes, accessRules);
this.junit = junit;
}

Expand All @@ -174,10 +220,13 @@ private static class JDTContainerClasspathEntry implements ClasspathContainerEnt

protected final String path;
protected final Map<String, String> attributes;
private List<ContainerAccessRule> accessRules;

public JDTContainerClasspathEntry(String path, Map<String, String> attributes) {
public JDTContainerClasspathEntry(String path, Map<String, String> attributes,
List<ContainerAccessRule> accessRules) {
this.path = path;
this.attributes = attributes;
this.accessRules = accessRules;
}

@Override
Expand All @@ -190,6 +239,11 @@ public String getContainerPath() {
return path;
}

@Override
public List<ContainerAccessRule> getAccessRules() {
return accessRules;
}

}

private static final class JDTOuput implements OutputClasspathEntry {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright (c) 2024 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.model.classpath;

import java.util.Objects;

public interface ContainerAccessRule {

public enum Kind {
ACCESSIBLE("accessible"), NON_ACCESSIBLE("nonaccessible"), DISCOURAGED("discouraged"), UNKNOWN("");

private String attribute;

Kind(String attribute) {
this.attribute = attribute;
}

static Kind parse(String value) {
for (Kind kind : values()) {
if (Objects.equals(kind.attribute, value)) {
return kind;
}
}
return Kind.UNKNOWN;
}

}

Kind getKind();

String getPattern();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import java.util.Collection;

public interface JREClasspathEntry extends ProjectClasspathEntry {
public interface JREClasspathEntry extends ClasspathContainerEntry {

static final String JRE_CONTAINER_PATH = "org.eclipse.jdt.launching.JRE_CONTAINER";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*******************************************************************************
* Copyright (c) 2024 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.model.classpath;

public interface PluginDependenciesClasspathContainer extends ClasspathContainerEntry {
static final String PATH = "org.eclipse.pde.core.requiredPlugins";
}