stream = StreamSupport
.stream(Spliterators.spliteratorUnknownSize(zip.entries().asIterator(), Spliterator.ORDERED), false);
return stream.filter(e -> e.getName().equals(name)).findAny();
-
}
@Test
@@ -113,31 +70,6 @@ public void testExtraSourceBundles() throws Exception {
assertTrue("Missing expected file", file.canRead());
}
- @Test
- public void testLicenseFeature() throws Exception {
- Verifier verifier = getVerifier("/sourcePlugin/license-feature", false, false);
- verifier.addCliOption("-De342-url=" + ECLIPSE_342.toString());
- verifier.executeGoals(List.of("clean", "install"));
- verifier.verifyErrorFreeLog();
- File sourceFeature = new File(verifier.getBasedir(), "feature/target/feature-1.0.0-sources-feature.jar");
- assertTrue("Missing expected file " + sourceFeature, sourceFeature.canRead());
- ZipFile featureZip = new ZipFile(sourceFeature);
- assertTrue("feature.properties not found in " + sourceFeature,
- findEntry(featureZip, "feature.properties").isPresent());
- // test for bug 403950
- assertTrue("license.html not found in " + sourceFeature, findEntry(featureZip, "license.html").isPresent());
- // test bug 395773
- Properties actual = new Properties();
- actual.load(featureZip.getInputStream(featureZip.getEntry("feature.properties")));
-
- // content must be merged from 1. license feature, 2. feature, 3. sourceTemplate
- assertEquals("feature label Developer Resources", actual.getProperty("label"));
- assertEquals("source feature description", actual.getProperty("description"));
- assertEquals("license feature copyright", actual.getProperty("copyright"));
- assertEquals("license.html", actual.getProperty("licenseURL"));
- assertEquals("license feature license", actual.getProperty("license"));
- }
-
@Test
public void testRemoteSourceBundles() throws Exception {
Verifier verifier = getVerifier("/sourcePlugin/remote-source-bundles", false, false);
diff --git a/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceFeatureMojo.java b/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceFeatureMojo.java
deleted file mode 100644
index 201d6d42b1..0000000000
--- a/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceFeatureMojo.java
+++ /dev/null
@@ -1,706 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2011, 2021 Sonatype Inc. 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:
- * Sonatype Inc. - initial API and implementation
- * Bachmann GmbH. - Bug 538395 Generate valid feature xml
- * Christoph Läubrich - Bug 568359 - move tycho-extras SourceFeatureMojo to tycho-source-feature
- *******************************************************************************/
-package org.eclipse.tycho.source;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-
-import org.apache.maven.archiver.MavenArchiveConfiguration;
-import org.apache.maven.archiver.MavenArchiver;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.Component;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.MavenProjectHelper;
-import org.codehaus.plexus.archiver.Archiver;
-import org.codehaus.plexus.archiver.FileSet;
-import org.codehaus.plexus.archiver.jar.JarArchiver;
-import org.codehaus.plexus.archiver.util.DefaultFileSet;
-import org.codehaus.plexus.configuration.PlexusConfiguration;
-import org.codehaus.plexus.logging.Logger;
-import org.codehaus.plexus.util.AbstractScanner;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.eclipse.tycho.BuildProperties;
-import org.eclipse.tycho.BuildPropertiesParser;
-import org.eclipse.tycho.PackagingType;
-import org.eclipse.tycho.ReproducibleUtils;
-import org.eclipse.tycho.TargetEnvironment;
-import org.eclipse.tycho.TargetPlatform;
-import org.eclipse.tycho.TychoConstants;
-import org.eclipse.tycho.core.TychoProjectManager;
-import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
-import org.eclipse.tycho.core.resolver.P2ResolutionResult;
-import org.eclipse.tycho.core.resolver.P2ResolutionResult.Entry;
-import org.eclipse.tycho.core.resolver.P2Resolver;
-import org.eclipse.tycho.core.resolver.P2ResolverFactory;
-import org.eclipse.tycho.model.Feature;
-import org.eclipse.tycho.model.FeatureRef;
-import org.eclipse.tycho.model.PluginRef;
-import org.eclipse.tycho.packaging.LicenseFeatureHelper;
-
-import de.pdark.decentxml.Document;
-import de.pdark.decentxml.Element;
-
-/**
- * Generates a source feature for projects of packaging type eclipse-feature. By
- * default, the generated source feature
- *
- * - Declares feature id
<originalFeatureId>.source
- * - Declares feature label
"<originalFeatureLabel> Developer Resources"
- * - If present, reuses feature provider, description, copyright and license as well as respective
- * URLs from <originalFeature>
- * - Includes all plugins included by <originalFeature>, but each with
.source
- * appended to each plugin id
- * - Includes all features included by <originalFeature>, but each with
.source
- * appended to each feature id
- * - Includes the original feature. This ensures that binaries and corresponding sources
- * match.
- *
- *
- * Source feature generation can be customized by adding files under path
- * sourceTemplateFeature/. Files added here will be added to the root of the source
- * feature jar. Especially, if file sourceTemplateFeature/feature.properties is found,
- * values in this file override values of respective keys in
- * <originalFeature>/feature.properties.
- *
- */
-@Mojo(name = SourceFeatureMojo.GOAL, defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true)
-public class SourceFeatureMojo extends AbstractMojo {
-
- static final String GOAL = "feature-source";
-
- public enum MissingSourcesAction {
- FAIL, WARN;
- }
-
- /**
- * Lock object to ensure thread-safety
- */
- private static final Object LOCK = new Object();
-
- public static final String FEATURE_TEMPLATE_DIR = "sourceTemplateFeature";
-
- public static final String SOURCES_FEATURE_CLASSIFIER = "sources-feature";
-
- private static final String FEATURE_PROPERTIES = "feature.properties";
-
- private static final String GEN_DIR = "sources-feature";
-
- @Parameter(property = "project", readonly = true)
- private MavenProject project;
-
- /**
- * Whether to skip source feature generation.
- */
- @Parameter(defaultValue = "false")
- private boolean skip;
-
- @Parameter(defaultValue = "WARN")
- private MissingSourcesAction missingSourcesAction = MissingSourcesAction.WARN;
-
- /**
- * Whether to add an include dependency from the source feature to the corresponding binary
- * feature. If true, this ensures the version of the installed sources matches the
- * binaries.
- */
- @Parameter(defaultValue = "true")
- private boolean includeBinaryFeature;
-
- /**
- * Source feature label suffix. Unless explicitly provided in
- * sourceTemplateFeature/feature.properties, this suffix will be appended to the
- * original feature label to construct the source feature label.
- */
- @Parameter(defaultValue = " Developer Resources")
- private String labelSuffix;
-
- /**
- * Use this to explicitly set the branding plugin attribute of the generated source feature (overrides
- * {@link #reuseBrandingPlugin}).
- */
- @Parameter
- private String brandingPlugin;
-
- /**
- * Whether to reuse an explicit branding plugin from the binary feature for the generated source
- * feature.
- */
- @Parameter(defaultValue = "true")
- private boolean reuseBrandingPlugin;
-
- /**
- * Bundles and features that do not have corresponding sources. Example:
- *
- *
- * <excludes>
- * <plugin id="plugin.nosource"/>
- * <feature id="feature.nosource"/>
- * </excludes>
- *
- *
- */
- @Parameter
- private PlexusConfiguration excludes;
-
- /**
- * Additional plugins to include in the generated source feature. Beware that these additional
- * plugins are not considered during build target platform calculation and ordering of reactor
- * projects. Use <extraRequirements> dependency resolver configuration to guarantee proper
- * reactor build order.
- *
- * WARNING This experimental parameter may be removed from future
- * source-feature mojo versions without prior notice.
- *
- */
- @Parameter
- private PlexusConfiguration plugins;
-
- @Parameter(defaultValue = "true")
- protected boolean useDefaultExcludes;
-
- @Parameter(property = "session", readonly = true)
- private MavenSession session;
-
- /**
- * Timestamp for reproducible output archive entries, either formatted as ISO 8601 extended
- * offset date-time (e.g. in UTC such as '2011-12-03T10:15:30Z' or with an offset
- * '2019-10-05T20:37:42+06:00'), or as an int representing seconds since the epoch (like
- * SOURCE_DATE_EPOCH).
- */
- @Parameter(defaultValue = "${project.build.outputTimestamp}")
- private String outputTimestamp;
-
- private final Set excludedPlugins = new HashSet<>();
-
- private final Set excludedFeatures = new HashSet<>();
-
- private final Set extraPlugins = new HashSet<>();
-
- @Parameter
- private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
-
- @Component
- private BuildPropertiesParser buildPropertiesParser;
-
- /**
- * The filename to be used for the generated archive file. For the source-feature goal,
- * "-sources-feature" is appended to this filename.
- */
- @Parameter(property = "project.build.finalName")
- private String finalName;
-
- @Component(role = Archiver.class, hint = "jar")
- private JarArchiver jarArchiver;
-
- @Component
- private MavenProjectHelper projectHelper;
-
- @Component
- private LicenseFeatureHelper licenseFeatureHelper;
-
- @Component()
- P2ResolverFactory factory;
-
- @Component
- private Logger logger;
-
- @Component
- private TychoProjectManager projectManager;
-
- @Override
- public void execute() throws MojoExecutionException, MojoFailureException {
- if (!PackagingType.TYPE_ECLIPSE_FEATURE.equals(project.getPackaging()) || skip) {
- return;
- }
- synchronized (LOCK) {
- try {
- Properties sourceFeatureTemplateProps = readSourceTemplateFeatureProperties();
- Properties mergedSourceFeatureProps = mergeFeatureProperties(sourceFeatureTemplateProps);
- File sourceFeatureXml = generateSourceFeatureXml(mergedSourceFeatureProps, sourceFeatureTemplateProps);
- ReproducibleUtils.storeProperties(mergedSourceFeatureProps,
- getMergedSourceFeaturePropertiesFile().toPath());
- MavenArchiver archiver = new MavenArchiver();
- archiver.setArchiver(jarArchiver);
- // configure for Reproducible Builds based on outputTimestamp value
- archiver.configureReproducibleBuild(outputTimestamp);
- File outputJarFile = getOutputJarFile();
- archiver.setOutputFile(outputJarFile);
- File template = new File(project.getBasedir(), FEATURE_TEMPLATE_DIR);
- if (template.isDirectory()) {
- DefaultFileSet templateFileSet = new DefaultFileSet();
- templateFileSet.setDirectory(template);
- // make sure we use generated feature.xml and feature.properties
- templateFileSet.setExcludes(new String[] { Feature.FEATURE_XML, FEATURE_PROPERTIES });
- archiver.getArchiver().addFileSet(templateFileSet);
- }
-
- BuildProperties buildProperties = buildPropertiesParser.parse(DefaultReactorProject.adapt(project));
- archiver.getArchiver().addFileSet(getManuallyIncludedFiles(project.getBasedir(), buildProperties));
-
- archiver.getArchiver().addFile(sourceFeatureXml, Feature.FEATURE_XML);
- archiver.getArchiver().addFile(getMergedSourceFeaturePropertiesFile(), FEATURE_PROPERTIES);
- File licenseFeature = licenseFeatureHelper
- .getLicenseFeature(Feature.read(new File(project.getBasedir(), "feature.xml")), project);
- if (licenseFeature != null) {
- archiver.getArchiver()
- .addArchivedFileSet(licenseFeatureHelper.getLicenseFeatureFileSet(licenseFeature));
- }
- archiver.createArchive(session, project, archive);
- projectHelper.attachArtifact(project, outputJarFile, SOURCES_FEATURE_CLASSIFIER);
- if (!isP2GenerationEnabled()) {
- logger.warn(
- """
- org.eclipse.tycho:tycho-p2-plugin seems not to be enabled but will be required if the generated source-feature is used in an update-site or another feature. You can add the following snippet to your pom:\s
-
- org.eclipse.tycho
- tycho-p2-plugin
-
-
- attach-p2-metadata
- package
-
- p2-metadata
-
-
-
-
- """);
- }
- } catch (MojoExecutionException e) {
- throw e;
- } catch (Exception e) {
- throw new MojoExecutionException("Could not package source feature jar", e);
- }
- }
- }
-
- protected boolean isP2GenerationEnabled() {
- Plugin plugin = project.getPlugin("org.eclipse.tycho:tycho-p2-plugin");
- return plugin != null && plugin.getExecutions().stream().anyMatch(e -> e.getGoals().contains("p2-metadata"));
- }
-
- static File getSourcesFeatureOutputDir(MavenProject project) {
- File dir = new File(project.getBuild().getDirectory(), GEN_DIR);
- dir.mkdirs();
- // TODO see https://github.com/eclipse-equinox/p2/issues/101
- new File(dir, "p2.inf").delete();
- return dir;
- }
-
- private Properties mergeFeatureProperties(Properties sourceFeatureTemplateProps) throws IOException {
- Properties generatedOriginalFeatureProps = readPropertiesIfExists(
- new File(project.getBuild().getDirectory(), FEATURE_PROPERTIES));
- Properties mergedProperties = new Properties();
- mergedProperties.putAll(generatedOriginalFeatureProps);
- mergedProperties.putAll(sourceFeatureTemplateProps);
- return mergedProperties;
- }
-
- private Properties readSourceTemplateFeatureProperties() throws IOException {
- return readPropertiesIfExists(new File(project.getBasedir(), FEATURE_TEMPLATE_DIR + "/" + FEATURE_PROPERTIES));
- }
-
- private File generateSourceFeatureXml(Properties mergedSourceFeatureProps, Properties sourceTemplateProps)
- throws IOException, MojoExecutionException {
- File sourceFeatureXml = new File(getSourcesFeatureOutputDir(project), Feature.FEATURE_XML);
- Feature feature = Feature.read(new File(this.project.getBuild().getDirectory(), "feature.xml"));
-
- final Feature sourceFeature = createSourceFeatureSkeleton(feature, mergedSourceFeatureProps,
- sourceTemplateProps);
- fillReferences(sourceFeature, feature, projectManager.getTargetPlatform(project)
- .orElseThrow(() -> new MojoExecutionException(TychoConstants.TYCHO_NOT_CONFIGURED + project)));
-
- Feature.write(sourceFeature, sourceFeatureXml, " ");
- return sourceFeatureXml;
- }
-
- private File getMergedSourceFeaturePropertiesFile() {
- return new File(getSourcesFeatureOutputDir(project), FEATURE_PROPERTIES);
- }
-
- private static Properties readPropertiesIfExists(File propertiesFile) throws IOException {
- Properties properties = new Properties();
- if (propertiesFile.isFile()) {
- try (FileInputStream propertiesStream = new FileInputStream(propertiesFile)) {
- properties.load(propertiesStream);
- }
- }
- return properties;
- }
-
- /**
- * This only create the new feature skeleton by setting labels and other not-structural values
- * that don't require platform resolution.
- */
- Feature createSourceFeatureSkeleton(Feature feature, Properties mergedFeatureProperties,
- Properties sourceTemplateProperties) throws IOException, MojoExecutionException {
- Document document = new Document();
- document.setEncoding("UTF-8");
- document.setRootNode(new Element("feature"));
- Feature sourceFeature = new Feature(document);
- sourceFeature.setId(feature.getId() + ".source");
- sourceFeature.setVersion(feature.getVersion());
- if (reuseBrandingPlugin && brandingPlugin == null) {
- if (feature.getBrandingPluginId() != null) {
- sourceFeature.setBrandingPluginId(feature.getBrandingPluginId());
- }
- } else if (brandingPlugin != null) {
- sourceFeature.setBrandingPluginId(brandingPlugin);
- }
-
- if (feature.getLabel() != null) {
- String originalLabel = feature.getLabel();
- if (originalLabel.startsWith("%")) {
- sourceFeature.setLabel(validateValue(originalLabel, mergedFeatureProperties));
- String labelKey = originalLabel.substring(1);
- if (sourceTemplateProperties.getProperty(labelKey) == null) {
- mergedFeatureProperties.setProperty(labelKey,
- mergedFeatureProperties.getProperty(labelKey) + labelSuffix);
- } else {
- // keep source template value
- }
- } else {
- sourceFeature.setLabel(originalLabel + labelSuffix);
- }
- }
- if (feature.getProvider() != null) {
- sourceFeature.setProvider(validateValue(feature.getProvider(), mergedFeatureProperties));
- }
- if (feature.getDescription() != null) {
- sourceFeature.setDescription(validateValue(feature.getDescription(), mergedFeatureProperties));
- }
- if (feature.getDescriptionURL() != null) {
- sourceFeature.setDescriptionURL(validateValue(feature.getDescriptionURL(), mergedFeatureProperties));
- }
- if (feature.getCopyright() != null) {
- sourceFeature.setCopyright(validateValue(feature.getCopyright(), mergedFeatureProperties));
- }
- if (feature.getCopyrightURL() != null) {
- sourceFeature.setCopyrightURL(validateValue(feature.getCopyrightURL(), mergedFeatureProperties));
- }
- if (feature.getLicense() != null) {
- sourceFeature.setLicense(validateValue(feature.getLicense(), mergedFeatureProperties));
- }
- if (feature.getLicenseURL() != null) {
- sourceFeature.setLicenseURL(validateValue(feature.getLicenseURL(), mergedFeatureProperties));
- }
-
- if (includeBinaryFeature) {
- FeatureRef binaryRef = new FeatureRef(new Element("includes"));
- binaryRef.setId(feature.getId());
- binaryRef.setVersion(feature.getVersion());
- if (feature.getOS() != null) {
- binaryRef.setOS(feature.getOS());
- }
- if (feature.getWS() != null) {
- binaryRef.setWS(feature.getWS());
- }
- if (feature.getArch() != null) {
- binaryRef.setArch(feature.getArch());
- }
- sourceFeature.addFeatureRef(binaryRef);
- }
-
- return sourceFeature;
- }
-
- /**
- * Returns the value for a field. In case the value is a reference to feature.properties, verify
- * that the entry exist in the feature.properties file for source
- *
- * @param fieldValue
- * @param sourceFeatureProperties
- * @return
- */
- private static String validateValue(String fieldValue, Properties sourceFeatureProperties)
- throws MojoExecutionException {
- if (fieldValue.startsWith("%")) {
- String key = fieldValue.substring(1);
- if (!sourceFeatureProperties.containsKey(key)) {
- throw new MojoExecutionException("Source feature depends on '" + FEATURE_TEMPLATE_DIR
- + "/feature.properties', entry '" + key + "'. However, this key could not be found");
- }
- }
- return fieldValue;
- }
-
- /**
- * Added all references to sourceFeature, as deduced by feature and resolved by targetPlatform
- *
- * @param sourceFeature
- * @param feature
- * @param targetPlatform
- * @throws MojoExecutionException
- */
- private void fillReferences(Feature sourceFeature, Feature feature, TargetPlatform targetPlatform)
- throws MojoExecutionException {
- P2Resolver p2 = factory.createResolver(Collections.singletonList(TargetEnvironment.getRunningEnvironment()));
-
- List missingSourcePlugins = new ArrayList<>();
- List missingSourceFeatures = new ArrayList<>();
- List missingExtraPlugins = new ArrayList<>();
-
- // include available source features
- for (FeatureRef featureRef : feature.getIncludedFeatures()) {
-
- if (excludedFeatures.contains(featureRef.getId())) {
- continue;
- }
-
- String sourceId = featureRef.getId() + ".source";
-
- // TODO 412416 either directly work on IUs (-> omit the "toResolutionResult" conversion), or ask for the Tycho artifact type ArtifactKey.TYPE_ECLIPSE_PLUGIN
- P2ResolutionResult result = p2.resolveInstallableUnit(targetPlatform, sourceId + ".feature.jar",
- toStrictVersionRange(featureRef.getVersion()));
- if (result.getArtifacts().size() == 1) {
- Entry entry = result.getArtifacts().iterator().next();
-
- FeatureRef sourceRef = new FeatureRef(new Element("includes"));
- sourceRef.setId(sourceId);
- sourceRef.setVersion(entry.getVersion());
- sourceFeature.addFeatureRef(sourceRef);
- } else {
- missingSourceFeatures.add(featureRef);
- }
- }
-
- // include available source bundles
- for (PluginRef pluginRef : feature.getPlugins()) {
-
- if (excludedPlugins.contains(pluginRef.getId())) {
- continue;
- }
-
- // version is expected to be fully expanded at this point
- P2ResolutionResult result = p2.resolveInstallableUnit(targetPlatform, pluginRef.getId() + ".source",
- toStrictVersionRange(pluginRef.getVersion()));
- if (result.getArtifacts().size() == 1) {
- addPlugin(sourceFeature, result, pluginRef);
- } else {
- missingSourcePlugins.add(pluginRef);
- }
- }
-
- for (PluginRef pluginRef : extraPlugins) {
- // version is expected to be fully expanded at this point
- P2ResolutionResult result = p2.resolveInstallableUnit(targetPlatform, pluginRef.getId(),
- pluginRef.getVersion());
- if (result.getArtifacts().size() == 1) {
- addPlugin(sourceFeature, result, pluginRef);
- } else {
- missingExtraPlugins.add(pluginRef);
- }
- }
-
- if (!missingSourceFeatures.isEmpty() || !missingSourcePlugins.isEmpty() || !missingExtraPlugins.isEmpty()) {
- if (missingSourcesAction == MissingSourcesAction.FAIL) {
- StringBuilder sb = new StringBuilder();
-
- sb.append("Could not generate source feature for project " + project.toString()).append("\n");
-
- if (!missingSourcePlugins.isEmpty()) {
- sb.append(" Missing sources for plugins " + missingSourcePlugins.toString()).append("\n");
- }
-
- if (!missingSourceFeatures.isEmpty()) {
- sb.append(" Missing sources for features " + missingSourceFeatures.toString()).append("\n");
- }
-
- if (!missingExtraPlugins.isEmpty()) {
- sb.append(" Missing extra plugins " + missingExtraPlugins.toString()).append("\n");
- }
-
- throw new MojoExecutionException(sb.toString());
- } else {
- reportMissing("The following referenced plugins have missing sources", missingSourcePlugins);
- reportMissing("The following referenced features have missing sources", missingSourceFeatures);
- reportMissing("The following referenced extra plugins have missing sources", missingExtraPlugins);
- }
- }
-
- }
-
- private void reportMissing(String msg, List> missing) {
- if (missing.isEmpty()) {
- return;
- }
- StringBuilder sb = new StringBuilder(msg);
- for (Object m : missing) {
- sb.append("\r\n\t");
- sb.append(m);
- }
- sb.append("\r\n");
- logger.warn(sb.toString());
- }
-
- protected String toStrictVersionRange(String version) {
- return "[" + version + "," + version + "]";
- }
-
- protected void addPlugin(Feature sourceFeature, P2ResolutionResult result, PluginRef pluginRef) {
- Entry sourceBundle = result.getArtifacts().iterator().next();
-
- PluginRef sourceRef = new PluginRef("plugin");
- sourceRef.setId(sourceBundle.getId());
- sourceRef.setVersion(sourceBundle.getVersion());
- if (pluginRef.getOs() != null) {
- sourceRef.setOs(pluginRef.getOs());
- }
- if (pluginRef.getWs() != null) {
- sourceRef.setWs(pluginRef.getWs());
- }
- if (pluginRef.getArch() != null) {
- sourceRef.setArch(pluginRef.getArch());
- }
- sourceFeature.addPlugin(sourceRef);
- }
-
- protected File getOutputJarFile() {
- String filename = finalName + "-" + SOURCES_FEATURE_CLASSIFIER + ".jar";
- return new File(project.getBuild().getDirectory(), filename);
- }
-
- // this is called by maven to inject value of configuration element
- public void setExcludes(PlexusConfiguration excludes) {
- for (PlexusConfiguration plugin : excludes.getChildren("plugin")) {
- String id = getAttribute(plugin, "id");
- if (id != null) {
- excludedPlugins.add(id);
- }
- // TODO warn about elements with null id
- }
- for (PlexusConfiguration plugin : excludes.getChildren("feature")) {
- String id = getAttribute(plugin, "id");
- if (id != null) {
- excludedFeatures.add(id);
- }
- // TODO warn about elements with null id
- }
- }
-
- // this is called by maven to inject value of configuration element
- public void setPlugins(PlexusConfiguration bundles) {
- for (PlexusConfiguration plugin : bundles.getChildren("plugin")) {
- String id = getAttribute(plugin, "id");
- if (id != null) {
- String version = getAttribute(plugin, "version");
- if (version == null) {
- version = "0.0.0";
- }
- PluginRef ref = new PluginRef("plugin");
- ref.setId(id);
- ref.setVersion(version);
- extraPlugins.add(ref);
- }
- // TODO fail if duplicate plugins
- // TODO warn about elements with null id
- }
- }
-
- private String getAttribute(PlexusConfiguration dom, String attrName) {
- String attr = dom.getAttribute(attrName);
- if (attr == null) {
- return null;
- }
- attr = attr.trim();
- if (attr.isEmpty()) {
- return null;
- }
- return attr;
- }
-
- /**
- * @return A {@link FileSet} including files as configured by the src.includes and
- * src.excludes properties without the files that are always included
- * automatically.
- */
- private FileSet getManuallyIncludedFiles(File basedir, BuildProperties buildProperties) {
- List srcExcludes = new ArrayList<>(buildProperties.getSourceExcludes());
- srcExcludes.add(Feature.FEATURE_XML); // we'll include updated feature.xml
- srcExcludes.add(FEATURE_PROPERTIES); // we'll include updated feature.properties
- return getFileSet(basedir, buildProperties.getSourceIncludes(), srcExcludes);
- }
-
- /**
- * @return a {@link FileSet} with the given includes and excludes and the configured default
- * excludes. An empty list of includes leads to an empty file set.
- */
- protected FileSet getFileSet(File basedir, List includes, List excludes) {
- DefaultFileSet fileSet = new DefaultFileSet();
- fileSet.setDirectory(basedir);
-
- if (includes.isEmpty()) {
- // FileSet interprets empty list as "everything", so we need to express "nothing" in a different way
- fileSet.setIncludes(new String[] { "" });
- } else {
- fileSet.setIncludes(includes.toArray(new String[includes.size()]));
- }
-
- Set allExcludes = new LinkedHashSet<>();
- if (excludes != null) {
- allExcludes.addAll(excludes);
- }
- if (useDefaultExcludes) {
- allExcludes.addAll(Arrays.asList(AbstractScanner.DEFAULTEXCLUDES));
- // keep ignoring the following files after https://github.com/codehaus-plexus/plexus-utils/pull/174
- allExcludes.add("**/.gitignore");
- allExcludes.add("**/.gitattributes");
- }
-
- fileSet.setExcludes(allExcludes.toArray(new String[allExcludes.size()]));
-
- return fileSet;
- }
-
- static boolean isEnabledForProject(MavenProject project) {
- if (!PackagingType.TYPE_ECLIPSE_FEATURE.equals(project.getPackaging())) {
- return false;
- }
- Plugin plugin = project.getPlugin("org.eclipse.tycho:tycho-source-plugin");
- if (plugin != null) {
- PluginExecution execution = plugin.getExecutions().stream()
- .filter(e -> e.getGoals().contains(SourceFeatureMojo.GOAL)).findFirst().orElse(null);
- if (execution == null) {
- return false;
- }
- Object configuration = execution.getConfiguration();
- if (configuration instanceof Xpp3Dom dom) {
- Xpp3Dom child = dom.getChild("skip");
- if (child != null && Boolean.valueOf(child.getValue())) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceFeatureP2MetadataProvider.java b/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceFeatureP2MetadataProvider.java
deleted file mode 100644
index 9583e3d81f..0000000000
--- a/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceFeatureP2MetadataProvider.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2011, 2020 Sonatype Inc. 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:
- * Sonatype Inc. - initial API and implementation
- * Christoph Läubrich - Bug 568359 - move tycho-extras SourceFeatureMojo to tycho-source-feature
- *******************************************************************************/
-package org.eclipse.tycho.source;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
-import org.codehaus.plexus.logging.Logger;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
-import org.eclipse.tycho.IArtifactFacade;
-import org.eclipse.tycho.IDependencyMetadata;
-import org.eclipse.tycho.OptionalResolutionAction;
-import org.eclipse.tycho.TargetEnvironment;
-import org.eclipse.tycho.model.Feature;
-import org.eclipse.tycho.model.FeatureRef;
-import org.eclipse.tycho.p2.metadata.DependencyMetadataGenerator;
-import org.eclipse.tycho.p2.metadata.PublisherOptions;
-import org.eclipse.tycho.p2resolver.AttachedArtifact;
-import org.eclipse.tycho.resolver.P2MetadataProvider;
-
-import de.pdark.decentxml.Document;
-import de.pdark.decentxml.Element;
-import de.pdark.decentxml.XMLDeclaration;
-
-@Component(role = P2MetadataProvider.class, hint = "org.eclipse.tycho.source.SourceFeatureP2MetadataProvider")
-public class SourceFeatureP2MetadataProvider implements P2MetadataProvider, Initializable {
- @Requirement
- private Logger log;
-
- @Requirement(hint = DependencyMetadataGenerator.DEPENDENCY_ONLY)
- private DependencyMetadataGenerator generator;
-
- @Override
- public Map getDependencyMetadata(MavenSession session, MavenProject project,
- List environments, OptionalResolutionAction optionalAction) {
- if (!SourceFeatureMojo.isEnabledForProject(project)) {
- return null;
- }
- try {
- File sourceFeatureBasedir = SourceFeatureMojo.getSourcesFeatureOutputDir(project);
- Feature sourceFeature = createPreliminarySourceFeature(project);
- Feature.write(sourceFeature, new File(sourceFeatureBasedir, Feature.FEATURE_XML));
- String classifier = SourceFeatureMojo.SOURCES_FEATURE_CLASSIFIER;
- IArtifactFacade artifact = new AttachedArtifact(project, sourceFeatureBasedir, classifier);
- return Collections.singletonMap(classifier, generator.generateMetadata(artifact, null,
- OptionalResolutionAction.REQUIRE, new PublisherOptions()));
- } catch (IOException e) {
- log.error("Could not create sources feature.xml", e);
- return null;
- }
-
- }
-
- static Feature createPreliminarySourceFeature(MavenProject project) throws IOException {
- /*
- * There is no easy way to determine what *exact* source bundles/features will be included
- * in the source feature at this point. Because of this, the source feature dependency-only
- * metadata does not include any dependencies.
- *
- * This has two implications.
- *
- * First, any missing source bundles/features will not be detected/reported until source
- * feature mojo is executed. This is inconsistent with how everything else works in Tycho,
- * but probably is a good thing.
- *
- * More importantly, though, source bundles/features are not included as transitive
- * dependencies of other reactor projects that include the source feature. To solve this for
- * eclipse-repository project, repository project dependencies are recalculated during
- * repository packaging. Other 'aggregating' project types, like eclipse-feature with
- * deployableFeature=true, will not be compatible with source features until
- * https://bugs.eclipse.org/bugs/show_bug.cgi?id=353889 is implemented.
- */
- Feature feature = Feature.read(new File(project.getBasedir(), "feature.xml"));
-
- Document document = new Document();
- document.setRootNode(new Element("feature"));
- document.setXmlDeclaration(new XMLDeclaration("1.0", "UTF-8"));
- Feature sourceFeature = new Feature(document);
-
- sourceFeature.setId(feature.getId() + ".source");
- sourceFeature.setVersion(feature.getVersion());
-
- // 410418 source feature includes binary feature
- FeatureRef binaryRef = new FeatureRef("includes");
- binaryRef.setId(feature.getId());
- binaryRef.setVersion(feature.getVersion());
- sourceFeature.addFeatureRef(binaryRef);
- return sourceFeature;
- }
-
- @Override
- public void initialize() throws InitializationException {
- }
-
-}
diff --git a/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceInstallableUnitProvider.java b/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceInstallableUnitProvider.java
index 5ae627f27e..8ef78a11de 100644
--- a/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceInstallableUnitProvider.java
+++ b/tycho-source-plugin/src/main/java/org/eclipse/tycho/source/SourceInstallableUnitProvider.java
@@ -12,8 +12,6 @@
*******************************************************************************/
package org.eclipse.tycho.source;
-import java.io.File;
-import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
@@ -26,19 +24,16 @@
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.publisher.IPublisherInfo;
-import org.eclipse.tycho.p2maven.tmp.BundlesAction;
-import org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.BuildPropertiesParser;
import org.eclipse.tycho.core.TychoProject;
import org.eclipse.tycho.core.osgitools.BundleReader;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
-import org.eclipse.tycho.model.Feature;
import org.eclipse.tycho.p2maven.InstallableUnitPublisher;
+import org.eclipse.tycho.p2maven.tmp.BundlesAction;
import org.eclipse.tycho.resolver.InstallableUnitProvider;
import org.osgi.framework.Constants;
@@ -63,20 +58,6 @@ public class SourceInstallableUnitProvider implements InstallableUnitProvider {
@Override
public Collection getInstallableUnits(MavenProject project, MavenSession session)
throws CoreException {
- if (SourceFeatureMojo.isEnabledForProject(project)) {
- try {
- //TODO even though we do not know the exact we might want to still fill in more infos here?
- File sourceFeatureBasedir = SourceFeatureMojo.getSourcesFeatureOutputDir(project);
- Feature sourceFeature = SourceFeatureP2MetadataProvider.createPreliminarySourceFeature(project);
- //TODO instead of writing it to file, we should use P2 Feature Objects directly!
- File file = new File(sourceFeatureBasedir, Feature.FEATURE_XML);
- Feature.write(sourceFeature, file);
- FeaturesAction featuresAction = new FeaturesAction(new File[] { sourceFeatureBasedir });
- return publisher.publishMetadata(List.of(featuresAction));
- } catch (IOException e) {
- throw new CoreException(Status.error("Creating preliminary source feature failed", e));
- }
- }
if (OsgiSourceMojo.isRelevant(project, buildPropertiesParser)) {
TychoProject projectType = projectTypes.get(project.getPackaging());
ArtifactKey artifactKey = projectType.getArtifactKey(DefaultReactorProject.adapt(project));
diff --git a/tycho-source-plugin/src/test/java/org/eclipse/tycho/source/SourceFeatureSkeletonTest.java b/tycho-source-plugin/src/test/java/org/eclipse/tycho/source/SourceFeatureSkeletonTest.java
deleted file mode 100644
index 06645f2990..0000000000
--- a/tycho-source-plugin/src/test/java/org/eclipse/tycho/source/SourceFeatureSkeletonTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2012, 2020 Red Hat Inc. 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:
- * Red Hat Inc. - initial API and implementation
- * Christoph Läubrich - Bug 568359 - move tycho-extras SourceFeatureMojo to tycho-source-feature
- *******************************************************************************/
-package org.eclipse.tycho.source;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.testing.AbstractMojoTestCase;
-import org.apache.maven.plugin.testing.SilentLog;
-import org.eclipse.tycho.model.Feature;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class SourceFeatureSkeletonTest extends AbstractMojoTestCase {
-
- private SourceFeatureMojo mojo;
-
- @Before
- @Override
- public void setUp() throws Exception {
- mojo = new SourceFeatureMojo();
- setVariableValueToObject(mojo, "logger", new SilentLog());
- setVariableValueToObject(mojo, "labelSuffix", " Developer Resources");
- }
-
- @Test
- public void testFeatureWithLabelInPropertiesDefaultSuffix() throws Exception {
- Feature originalFeature = createFeature("/featureWithLabelInProperties.xml");
- Assert.assertEquals("%label", originalFeature.getLabel());
- Properties sourceFeatureProperties = new Properties();
- Properties mergedProps = new Properties();
- mergedProps.setProperty("label", "feature label");
- Feature sourceFeature = mojo.createSourceFeatureSkeleton(originalFeature, mergedProps, sourceFeatureProperties);
- assertEquals("%label", sourceFeature.getLabel());
- assertEquals("feature label Developer Resources", mergedProps.getProperty("label"));
- }
-
- @Test
- public void testLabelOverriddenInSourceTemplate() throws Exception {
- Feature originalFeature = createFeature("/featureWithLabelInProperties.xml");
- Properties sourceFeatureProperties = new Properties();
- sourceFeatureProperties.setProperty("label", "source feature label");
- Properties mergedProps = new Properties();
- mergedProps.putAll(sourceFeatureProperties);
- Feature sourceFeature = mojo.createSourceFeatureSkeleton(originalFeature, mergedProps, sourceFeatureProperties);
- assertEquals("%label", sourceFeature.getLabel());
- assertEquals("source feature label", mergedProps.getProperty("label"));
- }
-
- @Test
- public void testFeatureLabelDefault() throws Exception {
- Feature originalFeature = createFeature("/featureWithHardcodedLabel.xml");
- assertEquals("a hardcoded label", originalFeature.getLabel());
- Properties emptyProps = new Properties();
- Feature sourceFeature = mojo.createSourceFeatureSkeleton(originalFeature, emptyProps, emptyProps);
- assertEquals("a hardcoded label Developer Resources", sourceFeature.getLabel());
- }
-
- @Test(expected = MojoExecutionException.class)
- public void testFeatureLabelMissingInProperties() throws Exception {
- Feature originalFeature = createFeature("/featureWithLabelInProperties.xml");
- Assert.assertEquals("%label", originalFeature.getLabel());
- Properties emptyProperties = new Properties();
- mojo.createSourceFeatureSkeleton(originalFeature, emptyProperties, emptyProperties);
- }
-
- private Feature createFeature(String fileName) throws IOException {
- try (InputStream featureStream = getClass().getResourceAsStream("/features" + fileName)) {
- return Feature.read(featureStream);
- }
- }
-
-}