diff --git a/tycho-compiler-plugin/src/main/java/org/eclipse/tycho/compiler/AbstractOsgiCompilerMojo.java b/tycho-compiler-plugin/src/main/java/org/eclipse/tycho/compiler/AbstractOsgiCompilerMojo.java index 5551f78b79..a169332e78 100644 --- a/tycho-compiler-plugin/src/main/java/org/eclipse/tycho/compiler/AbstractOsgiCompilerMojo.java +++ b/tycho-compiler-plugin/src/main/java/org/eclipse/tycho/compiler/AbstractOsgiCompilerMojo.java @@ -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; @@ -570,10 +573,19 @@ protected File getOutputDirectory() { @Override public List getClasspathElements() throws MojoExecutionException { + Collection classpathEntries = getEclipsePluginProject().getClasspathEntries(); final List classpath = new ArrayList<>(); Set seen = new HashSet<>(); Set includedPathes = new HashSet<>(); boolean useAccessRules = JDT_COMPILER_ID.equals(compilerId); + List 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 classpathLocations = Stream .concat(cpe.getLocations().stream(), @@ -582,7 +594,7 @@ public List 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); @@ -593,7 +605,6 @@ public List getClasspathElements() throws MojoExecutionException { ArtifactRepository repository = session.getLocalRepository(); if (repository != null) { String basedir = repository.getBasedir(); - Collection classpathEntries = getEclipsePluginProject().getClasspathEntries(); for (ProjectClasspathEntry cpe : classpathEntries) { if (cpe instanceof M2ClasspathVariable cpv) { String entry = new File(basedir, cpv.getRepositoryPath()).getAbsolutePath(); @@ -647,17 +658,33 @@ protected BundleProject getBundleProject() throws MojoExecutionException { return (BundleProject) projectType; } - private String toString(Collection rules, boolean useAccessRules) { + private String toString(Collection entryRules, List 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(); @@ -734,9 +761,9 @@ protected CompilerConfiguration getCompilerConfiguration(List compileSou compilerConfiguration.setReleaseVersion(releaseLevel); } configureJavaHome(compilerConfiguration); - configureBootclasspathAccessRules(compilerConfiguration); - configureCompilerLog(compilerConfiguration); Collection classpathEntries = getEclipsePluginProject().getClasspathEntries(); + configureBootclasspathAccessRules(compilerConfiguration, classpathEntries); + configureCompilerLog(compilerConfiguration); for (ProjectClasspathEntry cpe : classpathEntries) { if (cpe instanceof JREClasspathEntry jreClasspathEntry) { if (jreClasspathEntry.isModule()) { @@ -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 classpathEntries) throws MojoExecutionException { List accessRules = new ArrayList<>(); if (requireJREPackageImports != null) { @@ -815,8 +842,11 @@ private void configureBootclasspathAccessRules(CompilerConfiguration compilerCon .addAll(getBundleProject().getBootClasspathExtraAccessRules(DefaultReactorProject.adapt(project))); } if (!accessRules.isEmpty()) { + List 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)); } } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultClasspathEntry.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultClasspathEntry.java index 902de4300d..ae0434db2a 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultClasspathEntry.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/DefaultClasspathEntry.java @@ -66,6 +66,9 @@ public String getPattern() { @Override public String toString() { + if (isDiscouraged()) { + return getPattern() + " (discouraged)"; + } return getPattern(); } diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathContainerEntry.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathContainerEntry.java index ac540f89c5..3c106c1939 100644 --- a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathContainerEntry.java +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ClasspathContainerEntry.java @@ -12,6 +12,8 @@ *******************************************************************************/ package org.eclipse.tycho.model.classpath; +import java.util.List; + /** * represents a container classpath entry, this could be for example: * @@ -33,4 +35,10 @@ public interface ClasspathContainerEntry extends ProjectClasspathEntry { */ String getContainerPath(); + /** + * + * @return the {@link ContainerAccessRule}s defined for this classpathcontainer + */ + List getAccessRules(); + } 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 4a421b19d0..3d6f838cac 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,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; @@ -71,15 +75,18 @@ public static Collection parse(File basedir) throws IOExc new File(file.getParentFile(), output), attributes)); } else if ("con".equals(kind)) { String path = classpathentry.getAttribute("path"); + List 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"); @@ -100,6 +107,33 @@ public static Collection parse(File basedir) throws IOExc } } + private static List parseAccessRules(Element classpathentry) { + NodeList accessrules = classpathentry.getElementsByTagName("accessrule"); + Stream 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 getAttributes(Element parent) { Map map = new HashMap<>(); NodeList attributes = parent.getElementsByTagName("attribute"); @@ -111,10 +145,21 @@ private static Map getAttributes(Element parent) { return map; } + private static final class RequiredPluginsEntry extends JDTContainerClasspathEntry + implements PluginDependenciesClasspathContainer { + + public RequiredPluginsEntry(String path, Map attributes, + List accessRules) { + super(path, attributes, accessRules); + } + + } + private static final class JDTJREClasspathEntry extends JDTContainerClasspathEntry implements JREClasspathEntry { - public JDTJREClasspathEntry(String path, Map attributes) { - super(path, attributes); + public JDTJREClasspathEntry(String path, Map attributes, + List accessRules) { + super(path, attributes, accessRules); } @Override @@ -146,8 +191,9 @@ private static class JDTJUnitContainerClasspathEntry extends JDTContainerClasspa private final String junit; - public JDTJUnitContainerClasspathEntry(String path, String junit, Map attributes) { - super(path, attributes); + public JDTJUnitContainerClasspathEntry(String path, String junit, Map attributes, + List accessRules) { + super(path, attributes, accessRules); this.junit = junit; } @@ -174,10 +220,13 @@ private static class JDTContainerClasspathEntry implements ClasspathContainerEnt protected final String path; protected final Map attributes; + private List accessRules; - public JDTContainerClasspathEntry(String path, Map attributes) { + public JDTContainerClasspathEntry(String path, Map attributes, + List accessRules) { this.path = path; this.attributes = attributes; + this.accessRules = accessRules; } @Override @@ -190,6 +239,11 @@ public String getContainerPath() { return path; } + @Override + public List getAccessRules() { + return accessRules; + } + } private static final class JDTOuput implements OutputClasspathEntry { diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ContainerAccessRule.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ContainerAccessRule.java new file mode 100644 index 0000000000..d125e587b6 --- /dev/null +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/ContainerAccessRule.java @@ -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(); +} diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/JREClasspathEntry.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/JREClasspathEntry.java index d61beb7526..80d22477fc 100644 --- a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/JREClasspathEntry.java +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/JREClasspathEntry.java @@ -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"; diff --git a/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/PluginDependenciesClasspathContainer.java b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/PluginDependenciesClasspathContainer.java new file mode 100644 index 0000000000..90ad80881f --- /dev/null +++ b/tycho-metadata-model/src/main/java/org/eclipse/tycho/model/classpath/PluginDependenciesClasspathContainer.java @@ -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"; +}