From 3fce2864e3581dc7dbdd9511397f3dbdb73677e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Mon, 5 Feb 2024 18:26:41 +0100 Subject: [PATCH 1/2] Temporary Import BundlesAction form P2 --- .../tycho/p2maven/tmp/BundlesAction.java | 1177 +++++++++++++++++ 1 file changed, 1177 insertions(+) create mode 100644 p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tmp/BundlesAction.java diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tmp/BundlesAction.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tmp/BundlesAction.java new file mode 100644 index 0000000000..9731a12b14 --- /dev/null +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tmp/BundlesAction.java @@ -0,0 +1,1177 @@ +/******************************************************************************* + * Copyright (c) 2008, 2021 Code 9 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: + * Code 9 - initial API and implementation + * IBM - ongoing development + * SAP AG - make optional dependencies non-greedy by default; allow setting greedy through directive (bug 247099) + * Red Hat Inc. - Bug 460967 + * Christoph Läubrich - Bug 574952 p2 should distinguish between "product plugins" and "configuration plugins" (gently sponsored by Compart AG) + ******************************************************************************/ +package org.eclipse.tycho.p2maven.tmp; + +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.equinox.frameworkadmin.BundleInfo; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.internal.p2.metadata.ArtifactKey; +import org.eclipse.equinox.internal.p2.publisher.Messages; +import org.eclipse.equinox.internal.p2.publisher.eclipse.GeneratorBundleInfo; +import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; +import org.eclipse.equinox.p2.metadata.IInstallableUnitFragment; +import org.eclipse.equinox.p2.metadata.IProvidedCapability; +import org.eclipse.equinox.p2.metadata.IRequirement; +import org.eclipse.equinox.p2.metadata.IUpdateDescriptor; +import org.eclipse.equinox.p2.metadata.MetadataFactory; +import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; +import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitFragmentDescription; +import org.eclipse.equinox.p2.metadata.Version; +import org.eclipse.equinox.p2.metadata.VersionRange; +import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; +import org.eclipse.equinox.p2.publisher.AbstractPublisherAction; +import org.eclipse.equinox.p2.publisher.AdviceFileAdvice; +import org.eclipse.equinox.p2.publisher.IPublisherInfo; +import org.eclipse.equinox.p2.publisher.IPublisherResult; +import org.eclipse.equinox.p2.publisher.actions.IAdditionalInstallableUnitAdvice; +import org.eclipse.equinox.p2.publisher.actions.ICapabilityAdvice; +import org.eclipse.equinox.p2.publisher.actions.IPropertyAdvice; +import org.eclipse.equinox.p2.publisher.actions.ITouchpointAdvice; +import org.eclipse.equinox.p2.publisher.eclipse.IBundleShapeAdvice; +import org.eclipse.equinox.p2.query.IQueryResult; +import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; +import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; +import org.eclipse.equinox.spi.p2.publisher.LocalizationHelper; +import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; +import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.osgi.service.resolver.BundleSpecification; +import org.eclipse.osgi.service.resolver.ExportPackageDescription; +import org.eclipse.osgi.service.resolver.GenericDescription; +import org.eclipse.osgi.service.resolver.GenericSpecification; +import org.eclipse.osgi.service.resolver.HostSpecification; +import org.eclipse.osgi.service.resolver.ImportPackageSpecification; +import org.eclipse.osgi.service.resolver.StateObjectFactory; +import org.eclipse.osgi.util.ManifestElement; +import org.eclipse.osgi.util.NLS; +import org.eclipse.pde.internal.publishing.Activator; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.wiring.BundleRequirement; +import org.osgi.resource.Namespace; + +/** + * Publish IUs for all of the bundles in a given set of locations or described + * by a set of bundle descriptions. The locations can be actual locations of the + * bundles or folders of bundles. + * + * This action consults the following types of advice: + * + */ +@SuppressWarnings("restriction") +public class BundlesAction extends AbstractPublisherAction { + + public static final String FILTER_PROPERTY_INSTALL_SOURCE = "org.eclipse.update.install.sources"; //$NON-NLS-1$ + + public static final String INSTALL_SOURCE_FILTER = String.format("(%s=true)", FILTER_PROPERTY_INSTALL_SOURCE); //$NON-NLS-1$ + + /** + * A suffix used to match a bundle IU to its source + */ + public static final String SOURCE_SUFFIX = ".source"; //$NON-NLS-1$ + + /** + * A capability name in the {@link PublisherHelper#NAMESPACE_ECLIPSE_TYPE} + * namespace representing and OSGi bundle resource + * + * @see IProvidedCapability#getName() + */ + public static final String TYPE_ECLIPSE_BUNDLE = "bundle"; //$NON-NLS-1$ + + /** + * A capability name in the {@link PublisherHelper#NAMESPACE_ECLIPSE_TYPE} + * namespace representing a source bundle + * + * @see IProvidedCapability#getName() + */ + public static final String TYPE_ECLIPSE_SOURCE = "source"; //$NON-NLS-1$ + + public static final String OSGI_BUNDLE_CLASSIFIER = "osgi.bundle"; //$NON-NLS-1$ + public static final String CAPABILITY_NS_OSGI_BUNDLE = "osgi.bundle"; //$NON-NLS-1$ + public static final String CAPABILITY_NS_OSGI_FRAGMENT = "osgi.fragment"; //$NON-NLS-1$ + + public static final IProvidedCapability BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability( + PublisherHelper.NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, Version.createOSGi(1, 0, 0)); + public static final IProvidedCapability SOURCE_BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability( + PublisherHelper.NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_SOURCE, Version.createOSGi(1, 0, 0)); + + static final String DEFAULT_BUNDLE_LOCALIZATION = "OSGI-INF/l10n/bundle"; //$NON-NLS-1$ + + private static final String[] BUNDLE_IU_PROPERTY_MAP = { Constants.BUNDLE_NAME, IInstallableUnit.PROP_NAME, + Constants.BUNDLE_DESCRIPTION, IInstallableUnit.PROP_DESCRIPTION, Constants.BUNDLE_VENDOR, + IInstallableUnit.PROP_PROVIDER, Constants.BUNDLE_CONTACTADDRESS, IInstallableUnit.PROP_CONTACT, + Constants.BUNDLE_DOCURL, IInstallableUnit.PROP_DOC_URL, Constants.BUNDLE_UPDATELOCATION, + IInstallableUnit.PROP_BUNDLE_LOCALIZATION, Constants.BUNDLE_LOCALIZATION, + IInstallableUnit.PROP_BUNDLE_LOCALIZATION }; + public static final int BUNDLE_LOCALIZATION_INDEX = PublisherHelper.BUNDLE_LOCALIZED_PROPERTIES.length - 1; + public static final String DIR = "dir"; //$NON-NLS-1$ + public static final String JAR = "jar"; //$NON-NLS-1$ + public static final String BUNDLE_SHAPE = "Eclipse-BundleShape"; //$NON-NLS-1$ + + /** + * Manifest header directive for specifying how optional runtime requirements + * shall be handled during installation. + * + * @see #INSTALLATION_GREEDY + */ + public static final String INSTALLATION_DIRECTIVE = "x-installation"; //$NON-NLS-1$ + + /** + * Value for {@link #INSTALLATION_DIRECTIVE} indicating that an optional + * requirement shall be installed unless this is prevented by other mandatory + * requirements. Optional requirements without this directive value are ignored + * during installation. + */ + public static final String INSTALLATION_GREEDY = "greedy"; //$NON-NLS-1$ + + private File[] locations; + private BundleDescription[] bundles; + protected MultiStatus finalStatus; + + public static IArtifactKey createBundleArtifactKey(String bsn, String version) { + return new ArtifactKey(OSGI_BUNDLE_CLASSIFIER, bsn, Version.parseVersion(version)); + } + + public static IInstallableUnit createBundleConfigurationUnit(String hostId, Version cuVersion, + boolean isBundleFragment, GeneratorBundleInfo configInfo, String configurationFlavor, + IMatchExpression filter) { + return createBundleConfigurationUnit(hostId, cuVersion, isBundleFragment, configInfo, configurationFlavor, + filter, false); + } + + static IInstallableUnit createBundleConfigurationUnit(String hostId, Version cuVersion, + boolean isBundleFragment, GeneratorBundleInfo configInfo, String configurationFlavor, + IMatchExpression filter, boolean configOnly) { + if (configInfo == null) + return null; + + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = configurationFlavor + hostId; + cu.setId(configUnitId); + cu.setVersion(cuVersion); + + // Indicate the IU to which this CU apply + Version hostVersion = configOnly ? Version.emptyVersion : Version.parseVersion(configInfo.getVersion()); + VersionRange range = hostVersion == Version.emptyVersion ? VersionRange.emptyRange + : new VersionRange(hostVersion, true, Version.MAX_VERSION, true); + cu.setHost(new IRequirement[] { // + MetadataFactory.createRequirement(CAPABILITY_NS_OSGI_BUNDLE, hostId, range, null, false, false, true), // + MetadataFactory.createRequirement(PublisherHelper.NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, + new VersionRange(Version.createOSGi(1, 0, 0), true, Version.createOSGi(2, 0, 0), false), null, + false, false, false) }); + + // Adds capabilities for fragment, self, and describing the flavor supported + cu.setProperty(InstallableUnitDescription.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new IProvidedCapability[] { PublisherHelper.createSelfCapability(configUnitId, cuVersion), + MetadataFactory.createProvidedCapability(PublisherHelper.NAMESPACE_FLAVOR, configurationFlavor, + Version.createOSGi(1, 0, 0)) }); + + Map touchpointData = new HashMap<>(); + touchpointData.put("install", "installBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("uninstall", "uninstallBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("configure", createConfigScript(configInfo, isBundleFragment)); //$NON-NLS-1$ + touchpointData.put("unconfigure", createUnconfigScript(configInfo, isBundleFragment)); //$NON-NLS-1$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + cu.setFilter(filter); + return MetadataFactory.createInstallableUnit(cu); + } + + public static IInstallableUnit createBundleIU(BundleDescription bd, IArtifactKey key, IPublisherInfo info) { + return new BundlesAction(new BundleDescription[] { bd }).doCreateBundleIU(bd, key, info); + } + + protected IInstallableUnit doCreateBundleIU(BundleDescription bd, IArtifactKey key, IPublisherInfo publisherInfo) { + @SuppressWarnings("unchecked") + Map manifest = (Map) bd.getUserObject(); + + Map> manifestLocalizations = null; + if (manifest != null && bd.getLocation() != null) { + manifestLocalizations = getManifestLocalizations(manifest, new File(bd.getLocation())); + } + + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + iu.setSingleton(bd.isSingleton()); + iu.setId(bd.getSymbolicName()); + iu.setVersion(PublisherHelper.fromOSGiVersion(bd.getVersion())); + iu.setFilter(bd.getPlatformFilter()); + iu.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(bd.getSymbolicName(), + computeUpdateRange(bd.getVersion()), IUpdateDescriptor.NORMAL, null)); + iu.setArtifacts(new IArtifactKey[] { key }); + iu.setTouchpointType(PublisherHelper.TOUCHPOINT_OSGI); + + boolean isFragment = (bd.getHost() != null); + + // Gather requirements here + List requirements = new ArrayList<>(); + + // Process required fragment host + if (isFragment) { + requirements.add(MetadataFactory.createRequirement(CAPABILITY_NS_OSGI_BUNDLE, bd.getHost().getName(), + PublisherHelper.fromOSGiVersionRange(bd.getHost().getVersionRange()), null, false, false)); + } + + // Process required bundles + ManifestElement[] rawRequireBundleHeader = parseManifestHeader(Constants.REQUIRE_BUNDLE, manifest, + bd.getLocation()); + for (BundleSpecification requiredBundle : bd.getRequiredBundles()) { + addRequireBundleRequirement(requirements, requiredBundle, rawRequireBundleHeader); + } + + // Process the import packages + ManifestElement[] rawImportPackageHeader = parseManifestHeader(Constants.IMPORT_PACKAGE, manifest, + bd.getLocation()); + for (ImportPackageSpecification importedPackage : bd.getImportPackages()) { + if (!isDynamicImport(importedPackage)) { + addImportPackageRequirement(requirements, importedPackage, rawImportPackageHeader); + } + } + + // Process generic requirements + ManifestElement[] rawRequireCapHeader = parseManifestHeader(Constants.REQUIRE_CAPABILITY, manifest, + bd.getLocation()); + for (GenericSpecification requiredCap : bd.getGenericRequires()) { + addRequirement(requirements, requiredCap, rawRequireCapHeader, bd); + } + + // Create set of provided capabilities + List providedCapabilities = new ArrayList<>(); + + // Add identification capabilities + providedCapabilities.add(PublisherHelper.createSelfCapability(bd.getSymbolicName(), + PublisherHelper.fromOSGiVersion(bd.getVersion()))); + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_OSGI_BUNDLE, + bd.getSymbolicName(), PublisherHelper.fromOSGiVersion(bd.getVersion()))); + + // Process exported packages + for (ExportPackageDescription packageExport : bd.getExportPackages()) { + providedCapabilities + .add(MetadataFactory.createProvidedCapability(PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE, + packageExport.getName(), PublisherHelper.fromOSGiVersion(packageExport.getVersion()))); + } + + // Process generic capabilities + + // TODO + // IProvidedCapability may have to be extended to contain the OSGi directives as + // well which may be needed for + // Bug 360659, Bug 525368. E.g. with IProvidedCapability.getDirectives() + + // TODO + // It may be possible map the "osgi.identity" capability to elements of the IU + // like the id, the license, etc. + // It may be better to derive it at runtime. + + int capNo = 0; + for (GenericDescription genericCap : bd.getGenericCapabilities()) { + addCapability(providedCapabilities, genericCap, iu, capNo); + capNo++; + } + + // Add capability to describe the type of bundle + if (manifest != null && manifest.containsKey("Eclipse-SourceBundle")) { //$NON-NLS-1$ + providedCapabilities.add(SOURCE_BUNDLE_CAPABILITY); + } else { + providedCapabilities.add(BUNDLE_CAPABILITY); + // add an optional greedy disabled by default requirement to the source so a + // product or install agent can choose to include sources from a bundle + VersionRange strictRange = new VersionRange(iu.getVersion(), true, iu.getVersion(), true); + String sourceIu = iu.getId() + SOURCE_SUFFIX; + requirements.add(MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, sourceIu, strictRange, + INSTALL_SOURCE_FILTER, true, false, true)); + } + + // If needed add an additional capability to identify this as an OSGi fragment + if (isFragment) { + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_OSGI_FRAGMENT, + bd.getHost().getName(), PublisherHelper.fromOSGiVersion(bd.getVersion()))); + } + + if (manifestLocalizations != null) { + for (Entry> locEntry : manifestLocalizations.entrySet()) { + Locale locale = locEntry.getKey(); + Map translatedStrings = locEntry.getValue(); + for (Entry entry : translatedStrings.entrySet()) { + iu.setProperty(locale.toString() + '.' + entry.getKey(), entry.getValue()); + } + providedCapabilities.add(PublisherHelper.makeTranslationCapability(bd.getSymbolicName(), locale)); + } + } + iu.setRequirements(requirements.toArray(new IRequirement[requirements.size()])); + iu.setCapabilities(providedCapabilities.toArray(new IProvidedCapability[providedCapabilities.size()])); + + // Process advice + processUpdateDescriptorAdvice(iu, publisherInfo); + processCapabilityAdvice(iu, publisherInfo); + + // Set certain properties from the manifest header attributes as IU properties. + // The values of these attributes may be localized (strings starting with '%') + // with the translated values appearing in the localization IU fragments + // associated with the bundle IU. + if (manifest != null) { + int i = 0; + while (i < BUNDLE_IU_PROPERTY_MAP.length) { + if (manifest.containsKey(BUNDLE_IU_PROPERTY_MAP[i])) { + String value = manifest.get(BUNDLE_IU_PROPERTY_MAP[i]); + if (value != null && value.length() > 0) { + iu.setProperty(BUNDLE_IU_PROPERTY_MAP[i + 1], value); + } + } + i += 2; + } + } + + // Define the immutable metadata for this IU. In this case immutable means + // that this is something that will not impact the configuration. + Map touchpointData = new HashMap<>(); + touchpointData.put("manifest", toManifestString(manifest)); //$NON-NLS-1$ + if (isDir(bd, publisherInfo)) { + touchpointData.put("zipped", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // Process more advice + processTouchpointAdvice(iu, touchpointData, publisherInfo); + processInstallableUnitPropertiesAdvice(iu, publisherInfo); + + return MetadataFactory.createInstallableUnit(iu); + } + + @Deprecated + protected void addImportPackageRequirement(ArrayList reqsDeps, ImportPackageSpecification importSpec, + ManifestElement[] rawImportPackageHeader) { + addImportPackageRequirement((List) reqsDeps, importSpec, rawImportPackageHeader); + } + + protected void addImportPackageRequirement(List reqsDeps, ImportPackageSpecification importSpec, + ManifestElement[] rawImportPackageHeader) { + VersionRange versionRange = PublisherHelper.fromOSGiVersionRange(importSpec.getVersionRange()); + final boolean optional = isOptional(importSpec); + final boolean greedy; + if (optional) { + greedy = INSTALLATION_GREEDY.equals(getInstallationDirective(importSpec.getName(), rawImportPackageHeader)); + } else { + greedy = true; + } + // TODO this needs to be refined to take into account all the attribute handled + // by imports + reqsDeps.add(MetadataFactory.createRequirement(PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE, importSpec.getName(), + versionRange, null, optional, false, greedy)); + } + + @Deprecated + protected void addRequireBundleRequirement(ArrayList reqsDeps, BundleSpecification requiredBundle, + ManifestElement[] rawRequireBundleHeader) { + addRequireBundleRequirement((List) reqsDeps, requiredBundle, rawRequireBundleHeader); + } + + protected void addRequireBundleRequirement(List reqsDeps, BundleSpecification requiredBundle, + ManifestElement[] rawRequireBundleHeader) { + final boolean optional = requiredBundle.isOptional(); + final boolean greedy; + if (optional) { + greedy = INSTALLATION_GREEDY + .equals(getInstallationDirective(requiredBundle.getName(), rawRequireBundleHeader)); + } else { + greedy = true; + } + reqsDeps.add(MetadataFactory.createRequirement(CAPABILITY_NS_OSGI_BUNDLE, requiredBundle.getName(), + PublisherHelper.fromOSGiVersionRange(requiredBundle.getVersionRange()), null, optional ? 0 : 1, 1, + greedy)); + } + + // TODO Handle the "effective:=" directive somehow? + protected void addRequirement(List reqsDeps, GenericSpecification requireCapSpec, + ManifestElement[] rawRequireCapabilities) { + BundleRequirement req = requireCapSpec.getRequirement(); + + String namespace = req.getNamespace(); + Map directives = req.getDirectives(); + + String capFilter = directives.get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); + boolean optional = directives.get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE) == Namespace.RESOLUTION_OPTIONAL; + boolean greedy = optional ? INSTALLATION_GREEDY.equals(directives.get(INSTALLATION_DIRECTIVE)) : true; + + IRequirement requireCap = MetadataFactory.createRequirement(namespace, capFilter, null, optional ? 0 : 1, 1, + greedy); + reqsDeps.add(requireCap); + } + + protected void addRequirement(List reqsDeps, GenericSpecification requireCapSpec, + ManifestElement[] rawRequireCapabilities, BundleDescription bd) { + BundleRequirement req = requireCapSpec.getRequirement(); + + String namespace = req.getNamespace(); + Map directives = req.getDirectives(); + + String capFilter = directives.get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); + boolean optional = directives.get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE) == Namespace.RESOLUTION_OPTIONAL; + boolean greedy = optional ? INSTALLATION_GREEDY.equals(directives.get(INSTALLATION_DIRECTIVE)) : true; + + IRequirement requireCap = MetadataFactory.createRequirement(namespace, capFilter, null, optional ? 0 : 1, 1, + greedy, bd.getSymbolicName()); + reqsDeps.add(requireCap); + } + + protected void addCapability(List caps, GenericDescription provideCapDesc, + InstallableUnitDescription iu, int capNo) { + // Convert the values to String, Version, List of String or Version + Map capAttrs = provideCapDesc.getDeclaredAttributes().entrySet().stream() + .collect(toMap(Entry::getKey, e -> convertAttribute(e.getValue()))); + + // Resolve the namespace + String capNs = provideCapDesc.getType(); + + // Resolve the mandatory p2 name + // By convention OSGi capabilities have an attribute named like the capability + // namespace. + // If this is not the case synthesize a unique name (e.g. "osgi.service" has an + // "objectClass" attribute instead). + // TODO If present but not a String log a warning somehow that it is ignored? Or + // fail the publication? + capAttrs.compute(capNs, + (k, v) -> (v instanceof String) ? v : String.format("%s_%s-%s", iu.getId(), iu.getVersion(), capNo)); //$NON-NLS-1$ + + for (Version version : getVersions(capAttrs)) { + capAttrs.put(IProvidedCapability.PROPERTY_VERSION, version); // created capability contains a copy + caps.add(MetadataFactory.createProvidedCapability(capNs, capAttrs)); + } + } + + @SuppressWarnings("unchecked") + private Collection getVersions(Map capAttrs) { + // Resolve the mandatory p2 version + // By convention versioned OSGi capabilities have a "version" attribute + // containing the OSGi Version object + // If this is not the case use an empty version (e.g. "osgi.ee" has a list of + // versions). + Object versionValue = capAttrs.get(IProvidedCapability.PROPERTY_VERSION); + if (versionValue instanceof Version) { + return List.of((Version) versionValue); + } else if (versionValue instanceof Collection + && ((Collection) versionValue).stream().allMatch(Version.class::isInstance)) { + return (Collection) versionValue; + } else { + // TODO If present but not a Version log a warning somehow that it is ignored? + // Or fail the publication? + return List.of(Version.emptyVersion); + } + } + + private Object convertAttribute(Object attr) { + if (attr instanceof Collection) { + return ((Collection) attr).stream().map(this::convertScalarAttribute).collect(toList()); + } + return convertScalarAttribute(attr); + } + + private Object convertScalarAttribute(Object attr) { + if (attr instanceof org.osgi.framework.Version) { + org.osgi.framework.Version osgiVer = (org.osgi.framework.Version) attr; + return Version.createOSGi(osgiVer.getMajor(), osgiVer.getMinor(), osgiVer.getMicro(), + osgiVer.getQualifier()); + } + return attr.toString(); + } + + static VersionRange computeUpdateRange(org.osgi.framework.Version base) { + VersionRange updateRange = null; + if (!base.equals(org.osgi.framework.Version.emptyVersion)) { + updateRange = new VersionRange(Version.emptyVersion, true, PublisherHelper.fromOSGiVersion(base), false); + } else { + updateRange = VersionRange.emptyRange; + } + return updateRange; + } + + private IInstallableUnitFragment createHostLocalizationFragment(IInstallableUnit bundleIU, BundleDescription bd, + String hostId, String[] hostBundleManifestValues) { + Map> hostLocalizations = getHostLocalizations(new File(bd.getLocation()), + hostBundleManifestValues); + if (hostLocalizations == null || hostLocalizations.isEmpty()) + return null; + return createLocalizationFragmentOfHost(bd, hostId, hostBundleManifestValues, hostLocalizations); + } + + /* + * @param hostId + * + * @param bd + * + * @param locale + * + * @param localizedStrings + * + * @return installableUnitFragment + */ + private static IInstallableUnitFragment createLocalizationFragmentOfHost(BundleDescription bd, String hostId, + String[] hostManifestValues, Map> hostLocalizations) { + InstallableUnitFragmentDescription fragment = new MetadataFactory.InstallableUnitFragmentDescription(); + String fragmentId = makeHostLocalizationFragmentId(bd.getSymbolicName()); + fragment.setId(fragmentId); + fragment.setVersion(PublisherHelper.fromOSGiVersion(bd.getVersion())); // TODO: is this a meaningful version? + + HostSpecification hostSpec = bd.getHost(); + IRequirement[] hostReqs = new IRequirement[] { + MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, hostSpec.getName(), + PublisherHelper.fromOSGiVersionRange(hostSpec.getVersionRange()), null, false, false, false) }; + fragment.setHost(hostReqs); + + fragment.setSingleton(true); + fragment.setProperty(InstallableUnitDescription.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + + // Create a provided capability for each locale and add the translated + // properties. + ArrayList providedCapabilities = new ArrayList<>(hostLocalizations.size()); + providedCapabilities.add(PublisherHelper.createSelfCapability(fragmentId, fragment.getVersion())); + for (Entry> localeEntry : hostLocalizations.entrySet()) { + Locale locale = localeEntry.getKey(); + Map translatedStrings = localeEntry.getValue(); + for (Entry entry : translatedStrings.entrySet()) { + fragment.setProperty(locale.toString() + '.' + entry.getKey(), entry.getValue()); + } + providedCapabilities.add(PublisherHelper.makeTranslationCapability(hostId, locale)); + } + fragment.setCapabilities(providedCapabilities.toArray(new IProvidedCapability[providedCapabilities.size()])); + + return MetadataFactory.createInstallableUnitFragment(fragment); + } + + /** + * @return the id for the iu fragment containing localized properties for the + * fragment with the given id. + */ + private static String makeHostLocalizationFragmentId(String id) { + return id + ".translated_host_properties"; //$NON-NLS-1$ + } + + private static String createConfigScript(GeneratorBundleInfo configInfo, boolean isBundleFragment) { + if (configInfo == null) + return ""; //$NON-NLS-1$ + + String configScript = "";//$NON-NLS-1$ + if (!isBundleFragment && configInfo.getStartLevel() != BundleInfo.NO_LEVEL) { + configScript += "setStartLevel(startLevel:" + configInfo.getStartLevel() + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if (!isBundleFragment && configInfo.isMarkedAsStarted()) { + configScript += "markStarted(started: true);"; //$NON-NLS-1$ + } + + if (configInfo.getSpecialConfigCommands() != null) { + configScript += configInfo.getSpecialConfigCommands(); + } + + return configScript; + } + + private static String createDefaultBundleConfigScript(GeneratorBundleInfo configInfo) { + return createConfigScript(configInfo, false); + } + + public static IInstallableUnit createDefaultBundleConfigurationUnit(GeneratorBundleInfo configInfo, + GeneratorBundleInfo unconfigInfo, String configurationFlavor) { + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = PublisherHelper.createDefaultConfigUnitId(OSGI_BUNDLE_CLASSIFIER, configurationFlavor); + cu.setId(configUnitId); + Version configUnitVersion = Version.createOSGi(1, 0, 0); + cu.setVersion(configUnitVersion); + + // Add capabilities for fragment, self, and describing the flavor supported + cu.setProperty(InstallableUnitDescription.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities( + new IProvidedCapability[] { PublisherHelper.createSelfCapability(configUnitId, configUnitVersion), + MetadataFactory.createProvidedCapability(PublisherHelper.NAMESPACE_FLAVOR, configurationFlavor, + Version.createOSGi(1, 0, 0)) }); + + // Create a required capability on bundles + IRequirement[] reqs = new IRequirement[] { + MetadataFactory.createRequirement(PublisherHelper.NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, + VersionRange.emptyRange, null, false, true, false) }; + cu.setHost(reqs); + Map touchpointData = new HashMap<>(); + + touchpointData.put("install", "installBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("uninstall", "uninstallBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("configure", createDefaultBundleConfigScript(configInfo)); //$NON-NLS-1$ + touchpointData.put("unconfigure", createDefaultBundleUnconfigScript(unconfigInfo)); //$NON-NLS-1$ + + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + return MetadataFactory.createInstallableUnit(cu); + } + + private static String createDefaultBundleUnconfigScript(GeneratorBundleInfo unconfigInfo) { + return createUnconfigScript(unconfigInfo, false); + } + + private static String createUnconfigScript(GeneratorBundleInfo unconfigInfo, boolean isBundleFragment) { + if (unconfigInfo == null) + return ""; //$NON-NLS-1$ + String unconfigScript = "";//$NON-NLS-1$ + if (!isBundleFragment && unconfigInfo.getStartLevel() != BundleInfo.NO_LEVEL) { + unconfigScript += "setStartLevel(startLevel:" + BundleInfo.NO_LEVEL + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if (!isBundleFragment && unconfigInfo.isMarkedAsStarted()) { + unconfigScript += "markStarted(started: false);"; //$NON-NLS-1$ + } + + if (unconfigInfo.getSpecialUnconfigCommands() != null) { + unconfigScript += unconfigInfo.getSpecialUnconfigCommands(); + } + return unconfigScript; + } + + private static boolean isDynamicImport(ImportPackageSpecification importedPackage) { + return importedPackage.getDirective(Constants.RESOLUTION_DIRECTIVE) + .equals(ImportPackageSpecification.RESOLUTION_DYNAMIC); + } + + protected static boolean isOptional(ImportPackageSpecification importedPackage) { + return importedPackage.getDirective(Constants.RESOLUTION_DIRECTIVE) + .equals(ImportPackageSpecification.RESOLUTION_OPTIONAL); + } + + private static String toManifestString(Map p) { + if (p == null) + return null; + StringBuilder result = new StringBuilder(); + // See https://bugs.eclipse.org/329386. We are trying to reduce the size of the + // manifest data in + // the eclipse touchpoint. We've removed the code that requires it but in order + // for old clients + // to still be able to use recent repositories, we're going to keep around the + // manifest properties + // they need. + final String[] interestingKeys = new String[] { Constants.BUNDLE_SYMBOLICNAME, Constants.BUNDLE_VERSION, + Constants.FRAGMENT_HOST }; + for (String key : interestingKeys) { + String value = p.get(key); + if (value != null) + result.append(key).append(": ").append(value).append('\n'); //$NON-NLS-1$ + } + return result.length() == 0 ? null : result.toString(); + } + + // Return a map from locale to property set for the manifest localizations + // from the given bundle directory and given bundle localization path/name + // manifest property value. + private static Map> getManifestLocalizations(Map manifest, + File bundleLocation) { + Map> localizations; + Locale defaultLocale = null; // = Locale.ENGLISH; // TODO: get this from GeneratorInfo + String[] bundleManifestValues = getManifestCachedValues(manifest); + String bundleLocalization = bundleManifestValues[BUNDLE_LOCALIZATION_INDEX]; // Bundle localization is the last + // one in the list + + if ("jar".equalsIgnoreCase(IPath.fromOSString(bundleLocation.getName()).getFileExtension()) && //$NON-NLS-1$ + bundleLocation.isFile()) { + localizations = LocalizationHelper.getJarPropertyLocalizations(bundleLocation, bundleLocalization, + defaultLocale, bundleManifestValues); + // localizations = getJarManifestLocalization(bundleLocation, + // bundleLocalization, defaultLocale, bundleManifestValues); + } else { + localizations = LocalizationHelper.getDirPropertyLocalizations(bundleLocation, bundleLocalization, + defaultLocale, bundleManifestValues); + // localizations = getDirManifestLocalization(bundleLocation, + // bundleLocalization, defaultLocale, bundleManifestValues); + } + + return localizations; + } + + public static String[] getExternalizedStrings(IInstallableUnit iu) { + String[] result = new String[PublisherHelper.BUNDLE_LOCALIZED_PROPERTIES.length]; + int j = 0; + for (int i = 1; i < BUNDLE_IU_PROPERTY_MAP.length - 1; i += 2) { + if (iu.getProperty(BUNDLE_IU_PROPERTY_MAP[i]) != null + && iu.getProperty(BUNDLE_IU_PROPERTY_MAP[i]).length() > 0 + && iu.getProperty(BUNDLE_IU_PROPERTY_MAP[i]).charAt(0) == '%') + result[j++] = iu.getProperty(BUNDLE_IU_PROPERTY_MAP[i]).substring(1); + else + j++; + } + // The last string is the location + result[BUNDLE_LOCALIZATION_INDEX] = iu.getProperty(IInstallableUnit.PROP_BUNDLE_LOCALIZATION); + + return result; + } + + public static String[] getManifestCachedValues(Map manifest) { + String[] cachedValues = new String[PublisherHelper.BUNDLE_LOCALIZED_PROPERTIES.length]; + for (int j = 0; j < PublisherHelper.BUNDLE_LOCALIZED_PROPERTIES.length; j++) { + String value = manifest.get(PublisherHelper.BUNDLE_LOCALIZED_PROPERTIES[j]); + if (PublisherHelper.BUNDLE_LOCALIZED_PROPERTIES[j].equals(Constants.BUNDLE_LOCALIZATION)) { + if (value == null) + value = DEFAULT_BUNDLE_LOCALIZATION; + cachedValues[j] = value; + } else if (value != null && value.length() > 1 && value.charAt(0) == '%') { + cachedValues[j] = value.substring(1); + } + } + return cachedValues; + } + + // Return a map from locale to property set for the manifest localizations + // from the given bundle directory and given bundle localization path/name + // manifest property value. + public static Map> getHostLocalizations(File bundleLocation, + String[] hostBundleManifestValues) { + Map> localizations; + Locale defaultLocale = null; // = Locale.ENGLISH; // TODO: get this from GeneratorInfo + String hostBundleLocalization = hostBundleManifestValues[BUNDLE_LOCALIZATION_INDEX]; + if (hostBundleLocalization == null) + return null; + + if ("jar".equalsIgnoreCase(IPath.fromOSString(bundleLocation.getName()).getFileExtension()) && //$NON-NLS-1$ + bundleLocation.isFile()) { + localizations = LocalizationHelper.getJarPropertyLocalizations(bundleLocation, hostBundleLocalization, + defaultLocale, hostBundleManifestValues); + // localizations = getJarManifestLocalization(bundleLocation, + // hostBundleLocalization, defaultLocale, hostBundleManifestValues); + } else { + localizations = LocalizationHelper.getDirPropertyLocalizations(bundleLocation, hostBundleLocalization, + defaultLocale, hostBundleManifestValues); + // localizations = getDirManifestLocalization(bundleLocation, + // hostBundleLocalization, defaultLocale, hostBundleManifestValues); + } + + return localizations; + } + + public static BundleDescription createBundleDescription(Dictionary enhancedManifest, + File bundleLocation) { + try { + BundleDescription descriptor = StateObjectFactory.defaultFactory.createBundleDescription(null, + enhancedManifest, bundleLocation == null ? null : bundleLocation.getAbsolutePath(), 1); // TODO Do + // we need + // to have a + // real + // bundle id + descriptor.setUserObject(enhancedManifest); + return descriptor; + } catch (BundleException e) { + String message = NLS.bind(Messages.exception_stateAddition, + bundleLocation == null ? null : bundleLocation.getAbsoluteFile()); + IStatus status = new Status(IStatus.WARNING, Activator.ID, message, e); + LogHelper.log(status); + return null; + } + } + + /** + * @deprecated use {@link #createBundleDescription(File)} instead. + */ + @Deprecated + public static BundleDescription createBundleDescriptionIgnoringExceptions(File bundleLocation) { + try { + return createBundleDescription(bundleLocation); + } catch (IOException e) { + logWarning(bundleLocation, e); + return null; + } catch (BundleException e) { + logWarning(bundleLocation, e); + return null; + } + } + + private static void logWarning(File bundleLocation, Throwable t) { + String message = NLS.bind(Messages.exception_errorLoadingManifest, bundleLocation); + LogHelper.log(new Status(IStatus.WARNING, Activator.ID, message, t)); + } + + public static BundleDescription createBundleDescription(File bundleLocation) throws IOException, BundleException { + Dictionary manifest = loadManifest(bundleLocation); + if (manifest == null) + return null; + return createBundleDescription(manifest, bundleLocation); + } + + /** + * @deprecated use {@link #loadManifest(File)} instead. + */ + @Deprecated + public static Dictionary loadManifestIgnoringExceptions(File bundleLocation) { + try { + return loadManifest(bundleLocation); + } catch (IOException e) { + logWarning(bundleLocation, e); + return null; + } catch (BundleException e) { + logWarning(bundleLocation, e); + return null; + } + } + + public static Dictionary loadManifest(File bundleLocation) throws IOException, BundleException { + Dictionary manifest = basicLoadManifest(bundleLocation); + if (manifest == null) + return null; + // if the bundle itself does not define its shape, infer the shape from the + // current form + if (manifest.get(BUNDLE_SHAPE) == null) + manifest.put(BUNDLE_SHAPE, bundleLocation.isDirectory() ? DIR : JAR); + return manifest; + } + + /** + * @deprecated use {@link #basicLoadManifest(File)} instead. + */ + @Deprecated + public static Dictionary basicLoadManifestIgnoringExceptions(File bundleLocation) { + try { + return basicLoadManifest(bundleLocation); + } catch (IOException e) { + logWarning(bundleLocation, e); + return null; + } catch (BundleException e) { + logWarning(bundleLocation, e); + return null; + } + } + + public static Dictionary basicLoadManifest(File bundleLocation) + throws IOException, BundleException { + InputStream manifestStream = null; + ZipFile jarFile = null; + if ("jar".equalsIgnoreCase(IPath.fromOSString(bundleLocation.getName()).getFileExtension()) && bundleLocation.isFile()) { //$NON-NLS-1$ + jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); + ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME); + if (manifestEntry != null) { + manifestStream = jarFile.getInputStream(manifestEntry); + } + } else { + File manifestFile = new File(bundleLocation, JarFile.MANIFEST_NAME); + if (manifestFile.exists()) { + manifestStream = new BufferedInputStream(new FileInputStream(manifestFile)); + } + } + try { + if (manifestStream != null) { + return parseBundleManifestIntoModifyableDictionaryWithCaseInsensitiveKeys(manifestStream); + } + } finally { + try { + if (jarFile != null) + jarFile.close(); + } catch (IOException e2) { + // Ignore + } + } + + return null; + + } + + private static Dictionary parseBundleManifestIntoModifyableDictionaryWithCaseInsensitiveKeys( + InputStream manifestStream) throws IOException, BundleException { + CaseInsensitiveDictionaryMap map = new CaseInsensitiveDictionaryMap<>(10); + ManifestElement.parseBundleManifest(manifestStream, map); + return map; + } + + private static ManifestElement[] parseManifestHeader(String header, Map manifest, + String bundleLocation) { + try { + return ManifestElement.parseHeader(header, manifest.get(header)); + } catch (BundleException e) { + String message = NLS.bind(Messages.exception_errorReadingManifest, bundleLocation, e.getMessage()); + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, message, e)); + return null; + } + } + + private static String getInstallationDirective(String requirementId, ManifestElement[] correspondingBundleHeader) { + for (ManifestElement manifestElement : correspondingBundleHeader) { + String[] packages = manifestElement.getValueComponents(); + for (String pckg : packages) { + if (requirementId.equals(pckg)) { + return manifestElement.getDirective(INSTALLATION_DIRECTIVE); + } + } + } + // TODO this case indicates an internal error -> return assertion error status + return null; + } + + public BundlesAction(File[] locations) { + this.locations = locations; + } + + public BundlesAction(BundleDescription[] bundles) { + this.bundles = bundles; + } + + @Override + public IStatus perform(IPublisherInfo publisherInfo, IPublisherResult results, IProgressMonitor monitor) { + if (bundles == null && locations == null) + throw new IllegalStateException(Messages.exception_noBundlesOrLocations); + + setPublisherInfo(publisherInfo); + finalStatus = new MultiStatus(Activator.ID, IStatus.OK, Messages.message_bundlesPublisherMultistatus, null); + + try { + if (bundles == null) + bundles = getBundleDescriptions(expandLocations(locations), monitor); + generateBundleIUs(bundles, publisherInfo, results, monitor); + bundles = null; + } catch (OperationCanceledException e) { + return Status.CANCEL_STATUS; + } + if (!finalStatus.isOK()) { + return finalStatus; + } + return Status.OK_STATUS; + } + + protected void publishArtifact(IArtifactDescriptor descriptor, File base, File[] inclusions, + IPublisherInfo publisherInfo) { + IArtifactRepository destination = publisherInfo.getArtifactRepository(); + if (descriptor == null || destination == null) + return; + + // publish the given files + publishArtifact(descriptor, inclusions, null, publisherInfo, createRootPrefixComputer(base)); + } + + @Override + protected void publishArtifact(IArtifactDescriptor descriptor, File jarFile, IPublisherInfo publisherInfo) { + // no files to publish so this is done. + if (jarFile == null || publisherInfo == null) + return; + + // if the destination already contains the descriptor, there is nothing to do. + IArtifactRepository destination = publisherInfo.getArtifactRepository(); + if (destination == null || destination.contains(descriptor)) + return; + + super.publishArtifact(descriptor, jarFile, publisherInfo); + + } + + private File[] expandLocations(File[] list) { + ArrayList result = new ArrayList<>(); + expandLocations(list, result); + return result.toArray(new File[result.size()]); + } + + private void expandLocations(File[] list, ArrayList result) { + if (list == null) + return; + for (File location : list) { + if (location.isDirectory()) { + // if the location is itself a bundle, just add it. Otherwise r down + if (new File(location, JarFile.MANIFEST_NAME).exists()) + result.add(location); + else if (new File(location, "plugin.xml").exists() || new File(location, "fragment.xml").exists()) //$NON-NLS-1$ //$NON-NLS-2$ + result.add(location); // old style bundle without manifest + else + expandLocations(location.listFiles(), result); + } else { + result.add(location); + } + } + } + + /** + * Publishes bundle IUs to the p2 metadata and artifact repositories. + * + * @param bundleDescriptions Equinox framework descriptions of the bundles to + * publish. + * @param result Used to attach status for the publication + * operation. + * @param monitor Used to fire progress events. + * + * @deprecated Use + * {@link #generateBundleIUs(BundleDescription[] bundleDescriptions, IPublisherInfo info, IPublisherResult result, IProgressMonitor monitor)} + * with {@link IPublisherInfo} set to null + */ + @Deprecated + protected void generateBundleIUs(BundleDescription[] bundleDescriptions, IPublisherResult result, + IProgressMonitor monitor) { + generateBundleIUs(bundleDescriptions, null, result, monitor); + } + + /** + * Publishes bundle IUs to the p2 metadata and artifact repositories. + * + * @param bundleDescriptions Equinox framework descriptions of the bundles to + * publish. + * @param publisherInfo Configuration and publication advice information. + * @param result Used to attach status for the publication + * operation. + * @param monitor Used to fire progress events. + */ + protected void generateBundleIUs(BundleDescription[] bundleDescriptions, IPublisherInfo publisherInfo, + IPublisherResult result, IProgressMonitor monitor) { + // This assumes that hosts are processed before fragments because for each + // fragment the host + // is queried for the strings that should be translated. + for (BundleDescription bd : bundleDescriptions) { + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + + if (bd == null || bd.getSymbolicName() == null || bd.getVersion() == null) { + continue; + } + + // First check to see if there is already an IU around for this + IInstallableUnit bundleIU = queryForIU(result, bd.getSymbolicName(), + PublisherHelper.fromOSGiVersion(bd.getVersion())); + IArtifactKey bundleArtKey = createBundleArtifactKey(bd.getSymbolicName(), bd.getVersion().toString()); + if (bundleIU == null) { + createAdviceFileAdvice(bd, publisherInfo); + // Create the bundle IU according to any shape advice we have + bundleIU = doCreateBundleIU(bd, bundleArtKey, publisherInfo); + } + + File bundleLocation = new File(bd.getLocation()); + IArtifactDescriptor ad = PublisherHelper.createArtifactDescriptor(publisherInfo, bundleArtKey, bundleLocation); + processArtifactPropertiesAdvice(bundleIU, ad, publisherInfo); + + // Publish according to the shape on disk + if (bundleLocation.isDirectory()) { + publishArtifact(ad, bundleLocation, bundleLocation.listFiles(), publisherInfo); + } else { + publishArtifact(ad, bundleLocation, publisherInfo); + } + + IInstallableUnit fragment = null; + if (isFragment(bd)) { + String hostId = bd.getHost().getName(); + VersionRange hostVersionRange = PublisherHelper.fromOSGiVersionRange(bd.getHost().getVersionRange()); + + IQueryResult hosts = queryForIUs(result, hostId, hostVersionRange); + + for (IInstallableUnit host : hosts) { + String fragmentId = makeHostLocalizationFragmentId(bd.getSymbolicName()); + fragment = queryForIU(result, fragmentId, PublisherHelper.fromOSGiVersion(bd.getVersion())); + if (fragment == null) { + String[] externalizedStrings = getExternalizedStrings(host); + fragment = createHostLocalizationFragment(bundleIU, bd, hostId, externalizedStrings); + } + } + } + + result.addIU(bundleIU, IPublisherResult.ROOT); + if (fragment != null) { + result.addIU(fragment, IPublisherResult.NON_ROOT); + } + + InstallableUnitDescription[] others = processAdditionalInstallableUnitsAdvice(bundleIU, publisherInfo); + for (int iuIndex = 0; others != null && iuIndex < others.length; iuIndex++) { + result.addIU(MetadataFactory.createInstallableUnit(others[iuIndex]), IPublisherResult.ROOT); + } + } + } + + /** + * Adds advice for any p2.inf file found in this bundle. + */ + protected void createAdviceFileAdvice(BundleDescription bundleDescription, IPublisherInfo publisherInfo) { + String location = bundleDescription.getLocation(); + if (location == null) + return; + + AdviceFileAdvice advice = new AdviceFileAdvice(bundleDescription.getSymbolicName(), + PublisherHelper.fromOSGiVersion(bundleDescription.getVersion()), IPath.fromOSString(location), + AdviceFileAdvice.BUNDLE_ADVICE_FILE); + if (advice.containsAdvice()) + publisherInfo.addAdvice(advice); + + } + + private static boolean isDir(BundleDescription bundle, IPublisherInfo info) { + Collection advice = info.getAdvice(null, true, bundle.getSymbolicName(), + PublisherHelper.fromOSGiVersion(bundle.getVersion()), IBundleShapeAdvice.class); + // if the advice has a shape, use it + if (advice != null && !advice.isEmpty()) { + // we know there is some advice but if there is more than one, take the first. + String shape = advice.iterator().next().getShape(); + if (shape != null) + return shape.equals(IBundleShapeAdvice.DIR); + } + // otherwise go with whatever we figured out from the manifest or the shape on + // disk + @SuppressWarnings("unchecked") + Map manifest = (Map) bundle.getUserObject(); + String format = manifest.get(BUNDLE_SHAPE); + return DIR.equals(format); + } + + private boolean isFragment(BundleDescription bd) { + return (bd.getHost() != null ? true : false); + } + + protected BundleDescription[] getBundleDescriptions(File[] bundleLocations, IProgressMonitor monitor) { + if (bundleLocations == null) + return new BundleDescription[0]; + List result = new ArrayList<>(bundleLocations.length); + for (File bundleLocation : bundleLocations) { + if (monitor.isCanceled()) + throw new OperationCanceledException(); + BundleDescription description = null; + try { + description = createBundleDescription(bundleLocation); + } catch (IOException e) { + addPublishingErrorToFinalStatus(e, bundleLocation); + } catch (BundleException e) { + addPublishingErrorToFinalStatus(e, bundleLocation); + } + if (description != null) { + result.add(description); + } + } + return result.toArray(new BundleDescription[0]); + } + + private void addPublishingErrorToFinalStatus(Throwable t, File bundleLocation) { + finalStatus.add(new Status(IStatus.ERROR, Activator.ID, + NLS.bind(Messages.exception_errorPublishingBundle, bundleLocation, t.getMessage()), t)); + } +} From dd80a22b9f4fb50cae7d902406d09f8dcdb52bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Mon, 5 Feb 2024 18:59:49 +0100 Subject: [PATCH 2/2] Use imported BundlesAction where possible / adjust tests --- .../p2maven/InstallableUnitGenerator.java | 2 +- .../MavenProjectDependencyProcessor.java | 2 +- .../actions/BundleDependenciesAction.java | 2 +- ...eaturesAndBundlesPublisherApplication.java | 2 +- ...mConfigurationInstallableUnitProvider.java | 2 +- .../tycho/core/TychoProjectManager.java | 3 +- .../core/bnd/TargetPlatformRepository.java | 2 +- ...leRequirementsInstallableUnitProvider.java | 2 +- .../MavenTargetDefinitionContent.java | 2 +- .../resolver/target/ArtifactTypeHelper.java | 2 +- .../target/TargetPlatformFilterEvaluator.java | 2 +- .../resource/InstallableUnitCapability.java | 2 +- .../resource/InstallableUnitRequirement.java | 2 +- .../publisher/BundleDependenciesAction.java | 2 +- .../tycho/p2/resolver/BundlePublisher.java | 2 +- .../tycho/p2/resolver/FeatureGenerator.java | 2 +- .../resolver/FileTargetDefinitionContent.java | 2 +- .../AbstractDirectorApplicationCommand.java | 5 ++- .../AbstractResolutionStrategy.java | 3 +- .../tycho/p2resolver/P2GeneratorImpl.java | 2 +- .../p2resolver/P2ResolverFactoryImpl.java | 2 +- .../tycho/p2resolver/P2ResolverImpl.java | 2 +- .../p2resolver/RepositoryLocationContent.java | 2 +- ...rcesBundleDependencyMetadataGenerator.java | 2 +- .../P2DependencyGeneratorImplTest.java | 19 ++++++--- .../tycho/p2resolver/P2GeneratorImplTest.java | 41 +++++++++++-------- .../P2MetadataGeneratorImplTest.java | 2 +- .../tycho/test/util/InstallableUnitUtil.java | 2 +- .../EclipseBuildInstallableUnitProvider.java | 2 +- .../plugins/p2/director/DirectorMojo.java | 3 +- .../source/SourceInstallableUnitProvider.java | 2 +- ...BndTestBundlesInstallableUnitProvider.java | 2 +- .../bnd/TargetPlatformRepository.java | 2 +- 33 files changed, 73 insertions(+), 55 deletions(-) diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java index 1be5f3857e..5d89c5edf9 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/InstallableUnitGenerator.java @@ -53,7 +53,6 @@ import org.eclipse.equinox.p2.publisher.IPublisherAction; import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.PublisherInfo; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.Feature; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap; @@ -67,6 +66,7 @@ import org.eclipse.tycho.p2maven.actions.ProductDependenciesAction; import org.eclipse.tycho.p2maven.actions.ProductFile2; import org.eclipse.tycho.p2maven.io.MetadataIO; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.resolver.InstallableUnitProvider; import org.osgi.framework.Constants; import org.xml.sax.SAXException; diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java index d1000f3c84..c3c3d9dc41 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java @@ -43,10 +43,10 @@ import org.eclipse.equinox.p2.metadata.IProvidedCapability; import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.p2.query.CollectionResult; import org.eclipse.equinox.p2.query.IQueryable; import org.eclipse.tycho.p2maven.io.MetadataIO; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; /** * THis component computes dependencies between projects diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/BundleDependenciesAction.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/BundleDependenciesAction.java index b3af6f4c5e..39ac89161b 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/BundleDependenciesAction.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/actions/BundleDependenciesAction.java @@ -31,13 +31,13 @@ import org.eclipse.equinox.p2.publisher.AdviceFileParser; import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.actions.ICapabilityAdvice; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.BundleSpecification; import org.eclipse.osgi.service.resolver.ImportPackageSpecification; import org.eclipse.osgi.util.ManifestElement; import org.eclipse.tycho.OptionalResolutionAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; public class BundleDependenciesAction extends BundlesAction { diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tools/TychoFeaturesAndBundlesPublisherApplication.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tools/TychoFeaturesAndBundlesPublisherApplication.java index e0cd1dd752..9b02ae0665 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tools/TychoFeaturesAndBundlesPublisherApplication.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/tools/TychoFeaturesAndBundlesPublisherApplication.java @@ -46,13 +46,13 @@ import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.IPublisherResult; import org.eclipse.equinox.p2.publisher.PublisherInfo; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.p2.repository.IRepositoryManager; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; import org.eclipse.equinox.p2.repository.artifact.spi.ArtifactDescriptor; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.tycho.p2maven.advices.PGPSignatureAdvice; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.osgi.framework.BundleException; public class TychoFeaturesAndBundlesPublisherApplication extends AbstractPublisherApplication { diff --git a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationInstallableUnitProvider.java b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationInstallableUnitProvider.java index 87d6c83242..db8720fd9d 100644 --- a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationInstallableUnitProvider.java +++ b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationInstallableUnitProvider.java @@ -31,12 +31,12 @@ import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.core.TargetPlatformConfiguration; import org.eclipse.tycho.core.TychoProject; import org.eclipse.tycho.core.TychoProjectManager; import org.eclipse.tycho.core.resolver.DefaultTargetPlatformConfigurationReader; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.resolver.InstallableUnitProvider; /** diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java b/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java index 061d492d62..6a68efc9d9 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java @@ -62,6 +62,7 @@ import org.eclipse.tycho.core.resolver.shared.IncludeSourceMode; import org.eclipse.tycho.helper.PluginRealmHelper; import org.eclipse.tycho.model.project.EclipseProject; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.targetplatform.TargetDefinition; import aQute.bnd.osgi.Processor; @@ -164,7 +165,7 @@ private Map getProfileProperties(TargetEnvironment environment, properties.put("org.eclipse.update.install.features", "true"); IncludeSourceMode sourceMode = configuration.getTargetDefinitionIncludeSourceMode(); if (sourceMode == IncludeSourceMode.force || sourceMode == IncludeSourceMode.honor) { - properties.put("org.eclipse.update.install.sources", "true"); + properties.put(BundlesAction.FILTER_PROPERTY_INSTALL_SOURCE, "true"); } properties.putAll(configuration.getProfileProperties()); return properties; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/bnd/TargetPlatformRepository.java b/tycho-core/src/main/java/org/eclipse/tycho/core/bnd/TargetPlatformRepository.java index 0113d99378..ca35c59b80 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/bnd/TargetPlatformRepository.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/bnd/TargetPlatformRepository.java @@ -26,13 +26,13 @@ import org.codehaus.plexus.component.annotations.Requirement; import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.tycho.ArtifactKey; import org.eclipse.tycho.ArtifactType; import org.eclipse.tycho.TargetPlatform; import org.eclipse.tycho.TargetPlatformService; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import aQute.bnd.osgi.Instruction; import aQute.bnd.service.RepositoryPlugin; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/AdditionalBundleRequirementsInstallableUnitProvider.java b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/AdditionalBundleRequirementsInstallableUnitProvider.java index 187d8991ac..72303cf79d 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/AdditionalBundleRequirementsInstallableUnitProvider.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/AdditionalBundleRequirementsInstallableUnitProvider.java @@ -29,12 +29,12 @@ import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.MetadataFactory; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.tycho.BuildProperties; import org.eclipse.tycho.BuildPropertiesParser; import org.eclipse.tycho.ReactorProject; import org.eclipse.tycho.core.TychoProjectManager; import org.eclipse.tycho.core.osgitools.DefaultReactorProject; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.resolver.InstallableUnitProvider; import aQute.bnd.osgi.Constants; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/MavenTargetDefinitionContent.java b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/MavenTargetDefinitionContent.java index 3427c5f389..f55683c304 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/MavenTargetDefinitionContent.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/MavenTargetDefinitionContent.java @@ -57,7 +57,6 @@ import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.PublisherInfo; import org.eclipse.equinox.p2.publisher.actions.IPropertyAdvice; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.Feature; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; @@ -85,6 +84,7 @@ import org.eclipse.tycho.p2.resolver.WrappedArtifact; import org.eclipse.tycho.p2maven.advices.MavenChecksumAdvice; import org.eclipse.tycho.p2maven.advices.MavenPropertiesAdvice; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.targetplatform.TargetDefinition.BNDInstructions; import org.eclipse.tycho.targetplatform.TargetDefinition.MavenDependency; import org.eclipse.tycho.targetplatform.TargetDefinition.MavenGAVLocation; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/ArtifactTypeHelper.java b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/ArtifactTypeHelper.java index 5742b32f6e..a95f1ba7b3 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/ArtifactTypeHelper.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/ArtifactTypeHelper.java @@ -24,7 +24,7 @@ import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/TargetPlatformFilterEvaluator.java b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/TargetPlatformFilterEvaluator.java index 70437f18e3..aeb107b822 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/TargetPlatformFilterEvaluator.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/target/TargetPlatformFilterEvaluator.java @@ -22,7 +22,7 @@ import org.eclipse.equinox.p2.metadata.IProvidedCapability; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.eclipse.tycho.core.shared.MavenLogger; import org.eclipse.tycho.targetplatform.TargetPlatformFilter; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitCapability.java b/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitCapability.java index cccd1e42b6..9625841230 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitCapability.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitCapability.java @@ -18,7 +18,7 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IProvidedCapability; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.osgi.framework.Version; import org.osgi.framework.namespace.BundleNamespace; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitRequirement.java b/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitRequirement.java index 782fce6f05..fe175a9a0a 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitRequirement.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/osgi/resource/InstallableUnitRequirement.java @@ -21,7 +21,7 @@ import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.equinox.p2.metadata.expression.IMatchExpression; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.osgi.framework.namespace.BundleNamespace; import org.osgi.framework.namespace.PackageNamespace; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/publisher/BundleDependenciesAction.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/publisher/BundleDependenciesAction.java index c8d484628d..1987d0dccc 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2/publisher/BundleDependenciesAction.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/publisher/BundleDependenciesAction.java @@ -32,7 +32,7 @@ import org.eclipse.equinox.p2.publisher.AdviceFileParser; import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.actions.ICapabilityAdvice; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.BundleSpecification; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/BundlePublisher.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/BundlePublisher.java index 5880bddbde..14610aab4a 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/BundlePublisher.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/BundlePublisher.java @@ -33,7 +33,7 @@ import org.eclipse.equinox.p2.publisher.Publisher; import org.eclipse.equinox.p2.publisher.PublisherInfo; import org.eclipse.equinox.p2.publisher.actions.IPropertyAdvice; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FeatureGenerator.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FeatureGenerator.java index 4e14fc0695..b9a0c459cf 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FeatureGenerator.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FeatureGenerator.java @@ -45,7 +45,7 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IVersionedId; import org.eclipse.equinox.p2.metadata.VersionedId; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.Feature; import org.eclipse.tycho.core.MavenModelFacade; import org.eclipse.tycho.core.MavenModelFacade.MavenLicense; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FileTargetDefinitionContent.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FileTargetDefinitionContent.java index eecedab9b4..77c659176b 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FileTargetDefinitionContent.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/resolver/FileTargetDefinitionContent.java @@ -27,7 +27,7 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.PublisherInfo; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.Feature; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/director/shared/AbstractDirectorApplicationCommand.java b/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/director/shared/AbstractDirectorApplicationCommand.java index 6d59f72409..1d2acbd372 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/director/shared/AbstractDirectorApplicationCommand.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2/tools/director/shared/AbstractDirectorApplicationCommand.java @@ -25,6 +25,7 @@ import org.eclipse.tycho.DependencySeed; import org.eclipse.tycho.TargetEnvironment; import org.eclipse.tycho.p2.CommandLineArguments; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.p2tools.copiedfromp2.PhaseSetFactory; /** @@ -165,8 +166,8 @@ protected List getDirectorApplicationArguments() { public Map getProfileProperties() { Map props = new TreeMap<>(this.profileProperties); props.put("org.eclipse.update.install.features", Boolean.toString(installFeatures)); - if (installSources && props.get("org.eclipse.update.install.sources") == null) { - props.put("org.eclipse.update.install.sources", "true"); + if (installSources && props.get(BundlesAction.FILTER_PROPERTY_INSTALL_SOURCE) == null) { + props.put(BundlesAction.FILTER_PROPERTY_INSTALL_SOURCE, "true"); } return props; } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/AbstractResolutionStrategy.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/AbstractResolutionStrategy.java index ee2ee3b2ae..00cc30aa05 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/AbstractResolutionStrategy.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/AbstractResolutionStrategy.java @@ -33,6 +33,7 @@ import org.eclipse.tycho.TargetEnvironment; import org.eclipse.tycho.core.shared.MavenLogger; import org.eclipse.tycho.p2.resolver.ResolverException; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; public abstract class AbstractResolutionStrategy { protected static final IInstallableUnit[] EMPTY_IU_ARRAY = new IInstallableUnit[0]; @@ -71,7 +72,7 @@ protected abstract Collection resolve(Map prop private Map getEffectiveFilterProperties(TargetEnvironment environment) { Map result = environment.toFilterProperties(); result.put("org.eclipse.update.install.features", "true"); - result.put("org.eclipse.update.install.sources", "true"); + result.put(BundlesAction.FILTER_PROPERTY_INSTALL_SOURCE, "true"); insertAdditionalFilterProperties(result); return result; } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2GeneratorImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2GeneratorImpl.java index 4bc5cfa261..7ba3c924d0 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2GeneratorImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2GeneratorImpl.java @@ -54,7 +54,7 @@ import org.eclipse.equinox.p2.publisher.IPublisherResult; import org.eclipse.equinox.p2.publisher.PublisherInfo; import org.eclipse.equinox.p2.publisher.actions.IFeatureRootAdvice; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.Feature; import org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverFactoryImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverFactoryImpl.java index ae112056b5..89434459ab 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverFactoryImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverFactoryImpl.java @@ -38,7 +38,7 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IProvidedCapability; import org.eclipse.equinox.p2.metadata.IRequirement; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.tycho.ArtifactDescriptor; import org.eclipse.tycho.IRepositoryIdManager; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverImpl.java index 21db213c82..c1b90daef8 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/P2ResolverImpl.java @@ -41,7 +41,7 @@ import org.eclipse.equinox.p2.metadata.MetadataFactory; import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.IQueryable; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/RepositoryLocationContent.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/RepositoryLocationContent.java index ed971f8a90..8a0768ca84 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/RepositoryLocationContent.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/RepositoryLocationContent.java @@ -32,7 +32,7 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.PublisherInfo; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.equinox.p2.publisher.eclipse.Feature; import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/SourcesBundleDependencyMetadataGenerator.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/SourcesBundleDependencyMetadataGenerator.java index c4a9defda0..7d9fd7327e 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/SourcesBundleDependencyMetadataGenerator.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/SourcesBundleDependencyMetadataGenerator.java @@ -24,7 +24,7 @@ import org.eclipse.equinox.p2.publisher.IPublisherAdvice; import org.eclipse.equinox.p2.publisher.IPublisherInfo; import org.eclipse.equinox.p2.publisher.PublisherInfo; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.StateObjectFactory; import org.eclipse.tycho.BuildPropertiesParser; diff --git a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2DependencyGeneratorImplTest.java b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2DependencyGeneratorImplTest.java index 8b44c5cb6c..a6d05dae0e 100644 --- a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2DependencyGeneratorImplTest.java +++ b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2DependencyGeneratorImplTest.java @@ -79,7 +79,7 @@ public void bundle() throws Exception { assertEquals("org.eclipse.tycho.p2.impl.test.bundle", unit.getId()); assertEquals("1.0.0.qualifier", unit.getVersion().toString()); - assertEquals(3, unit.getRequirements().size()); + assertEquals(4, unit.getRequirements().size()); assertEquals(DEFAULT_CLASSIFIER, unit.getProperty(TychoConstants.PROP_CLASSIFIER)); // not really necessary, but we get this because we reuse standard p2 implementation @@ -97,14 +97,21 @@ public void bundle_with_p2_inf() throws Exception { assertEquals("1.0.0.qualifier", unit.getVersion().toString()); List requirements = new ArrayList<>(unit.getRequirements()); - assertEquals(1, requirements.size()); - IRequiredCapability requirement = (IRequiredCapability) requirements.get(0); - assertEquals(IInstallableUnit.NAMESPACE_IU_ID, requirement.getNamespace()); - assertEquals("required.p2.inf", requirement.getName()); - + assertNotNull(getReqCap(requirements, IInstallableUnit.NAMESPACE_IU_ID, "required.p2.inf")); assertNotNull(getUnitWithId("iu.p2.inf", units)); } + private IRequiredCapability getReqCap(List requirements, String ns, String name) { + for (IRequirement r : requirements) { + if (r instanceof IRequiredCapability cap) { + if (ns.equals(cap.getNamespace()) && name.equals(cap.getName())) { + return cap; + } + } + } + return null; + } + private IInstallableUnit getUnitWithId(String id, List units) { for (IInstallableUnit unit : units) { if (id.equals(unit.getId())) { diff --git a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2GeneratorImplTest.java b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2GeneratorImplTest.java index a7bd17a538..a48ddf57ce 100644 --- a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2GeneratorImplTest.java +++ b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2GeneratorImplTest.java @@ -34,12 +34,12 @@ import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.equinox.p2.metadata.ITouchpointData; import org.eclipse.equinox.p2.metadata.Version; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; import org.eclipse.equinox.spi.p2.publisher.PublisherHelper; import org.eclipse.tycho.OptionalResolutionAction; import org.eclipse.tycho.TargetEnvironment; import org.eclipse.tycho.p2.metadata.DependencyMetadataGenerator; import org.eclipse.tycho.p2.metadata.PublisherOptions; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.test.util.ArtifactMock; import org.eclipse.tycho.test.util.BuildPropertiesParserForTesting; import org.eclipse.tycho.test.util.LogVerifier; @@ -117,8 +117,9 @@ public void testOptionalImportPackage_REQUIRE() throws Exception { IInstallableUnit iu = getUnit("optional-import-package", units); assertNotNull(iu); List requirements = new ArrayList<>(iu.getRequirements()); - assertEquals(1, requirements.size()); - IRequiredCapability requirement = (IRequiredCapability) requirements.get(0); + IRequiredCapability requirement = getReqCap(requirements, PublisherHelper.CAPABILITY_NS_JAVA_PACKAGE, + "org.osgi.framework"); + assertNotNull("org.osgi.framework", requirement); assertTrue(requirement.isGreedy()); assertEquals(1, requirement.getMin()); assertEquals(1, requirement.getMax()); @@ -126,6 +127,17 @@ public void testOptionalImportPackage_REQUIRE() throws Exception { assertEquals("org.osgi.framework", requirement.getName()); } + private IRequiredCapability getReqCap(List requirements, String ns, String name) { + for (IRequirement r : requirements) { + if (r instanceof IRequiredCapability cap) { + if (ns.equals(cap.getNamespace()) && name.equals(cap.getName())) { + return cap; + } + } + } + return null; + } + private DefaultDependencyMetadataGenerator createDependencyMetadataGenerator() { DefaultDependencyMetadataGenerator generator = new DefaultDependencyMetadataGenerator(); generator.setBuildPropertiesParser(new BuildPropertiesParserForTesting()); @@ -145,7 +157,7 @@ public void testOptionalImportPackage_IGNORE() throws Exception { IInstallableUnit iu = getUnit("optional-import-package", units); assertNotNull(iu); List requirements = new ArrayList<>(iu.getRequirements()); - assertEquals(0, requirements.size()); + assertEquals(1, requirements.size()); } @Test @@ -160,13 +172,12 @@ public void testOptionalRequireBundle_REQUIRE() throws Exception { IInstallableUnit iu = getUnit("optional-require-bundle", units); assertNotNull(iu); List requirements = new ArrayList<>(iu.getRequirements()); - assertEquals(1, requirements.size()); - IRequiredCapability requirement = (IRequiredCapability) requirements.get(0); + IRequiredCapability requirement = getReqCap(requirements, BundlesAction.CAPABILITY_NS_OSGI_BUNDLE, + "org.eclipse.osgi"); + assertNotNull(requirement); assertTrue(requirement.isGreedy()); assertEquals(1, requirement.getMin()); assertEquals(1, requirement.getMax()); - assertEquals(BundlesAction.CAPABILITY_NS_OSGI_BUNDLE, requirement.getNamespace()); - assertEquals("org.eclipse.osgi", requirement.getName()); } @Test @@ -181,13 +192,11 @@ public void testOptionalRequireBundle_OPTIONAL() throws Exception { IInstallableUnit iu = getUnit("optional-require-bundle", units); assertNotNull(iu); List requirements = new ArrayList<>(iu.getRequirements()); - assertEquals(1, requirements.size()); - IRequiredCapability requirement = (IRequiredCapability) requirements.get(0); + IRequiredCapability requirement = getReqCap(requirements, BundlesAction.CAPABILITY_NS_OSGI_BUNDLE, + "org.eclipse.osgi"); assertFalse(requirement.isGreedy()); assertEquals(0, requirement.getMin()); assertEquals(1, requirement.getMax()); - assertEquals(BundlesAction.CAPABILITY_NS_OSGI_BUNDLE, requirement.getNamespace()); - assertEquals("org.eclipse.osgi", requirement.getName()); } @Test @@ -202,7 +211,7 @@ public void testOptionalRequireBundle_IGNORE() throws Exception { IInstallableUnit iu = getUnit("optional-require-bundle", units); assertNotNull(iu); List requirements = new ArrayList<>(iu.getRequirements()); - assertEquals(0, requirements.size()); + assertEquals(1, requirements.size()); } @Test @@ -217,12 +226,10 @@ public void testOptionalRequireBundleP2inf_REQUIRE() throws Exception { IInstallableUnit iu = getUnit("optional-reqiure-bundle-p2inf", units); assertNotNull(iu); List requirements = new ArrayList<>(iu.getRequirements()); - assertEquals(1, requirements.size()); - IRequiredCapability requirement = (IRequiredCapability) requirements.get(0); + IRequiredCapability requirement = getReqCap(requirements, BundlesAction.CAPABILITY_NS_OSGI_BUNDLE, + "org.eclipse.osgi"); assertTrue(requirement.isGreedy()); assertEquals(1, requirement.getMin()); assertEquals(1, requirement.getMax()); - assertEquals(BundlesAction.CAPABILITY_NS_OSGI_BUNDLE, requirement.getNamespace()); - assertEquals("org.eclipse.osgi", requirement.getName()); } } diff --git a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2MetadataGeneratorImplTest.java b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2MetadataGeneratorImplTest.java index 63669c9037..55a62d63bc 100644 --- a/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2MetadataGeneratorImplTest.java +++ b/tycho-core/src/test/java/org/eclipse/tycho/p2resolver/P2MetadataGeneratorImplTest.java @@ -61,7 +61,7 @@ public void gav() throws Exception { Assert.assertEquals("org.eclipse.tycho.p2.impl.test.bundle", unit.getId()); Assert.assertEquals("1.0.0.qualifier", unit.getVersion().toString()); - Assert.assertEquals(3, unit.getRequirements().size()); + Assert.assertEquals(4, unit.getRequirements().size()); Assert.assertEquals(1, artifacts.size()); IArtifactDescriptor ad = artifacts.iterator().next(); diff --git a/tycho-core/src/test/java/org/eclipse/tycho/test/util/InstallableUnitUtil.java b/tycho-core/src/test/java/org/eclipse/tycho/test/util/InstallableUnitUtil.java index 9236e3837b..caec2fe134 100644 --- a/tycho-core/src/test/java/org/eclipse/tycho/test/util/InstallableUnitUtil.java +++ b/tycho-core/src/test/java/org/eclipse/tycho/test/util/InstallableUnitUtil.java @@ -26,7 +26,7 @@ import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; public class InstallableUnitUtil { diff --git a/tycho-eclipse-plugin/src/main/java/org/eclipse/tycho/eclipsebuild/EclipseBuildInstallableUnitProvider.java b/tycho-eclipse-plugin/src/main/java/org/eclipse/tycho/eclipsebuild/EclipseBuildInstallableUnitProvider.java index f904e5aeec..037eedc360 100644 --- a/tycho-eclipse-plugin/src/main/java/org/eclipse/tycho/eclipsebuild/EclipseBuildInstallableUnitProvider.java +++ b/tycho-eclipse-plugin/src/main/java/org/eclipse/tycho/eclipsebuild/EclipseBuildInstallableUnitProvider.java @@ -24,7 +24,7 @@ import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.MetadataFactory; import org.eclipse.equinox.p2.metadata.VersionRange; -import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.helper.PluginConfigurationHelper; import org.eclipse.tycho.helper.PluginConfigurationHelper.Configuration; import org.eclipse.tycho.resolver.InstallableUnitProvider; diff --git a/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/DirectorMojo.java b/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/DirectorMojo.java index 04bdc2ed13..1256cf111e 100644 --- a/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/DirectorMojo.java +++ b/tycho-p2-director-plugin/src/main/java/org/eclipse/tycho/plugins/p2/director/DirectorMojo.java @@ -45,6 +45,7 @@ import org.eclipse.tycho.p2.CommandLineArguments; import org.eclipse.tycho.p2.resolver.BundlePublisher; import org.eclipse.tycho.p2.tools.director.shared.DirectorRuntime; +import org.eclipse.tycho.p2maven.tmp.BundlesAction; import org.eclipse.tycho.p2tools.MavenDirectorLog; import org.eclipse.tycho.p2tools.copiedfromp2.DirectorApplication; import org.eclipse.tycho.p2tools.copiedfromp2.PhaseSetFactory; @@ -477,7 +478,7 @@ private Map getPropertyMap(String csvPropertiesMap, Map