Skip to content

Commit

Permalink
Add optional, greedy and disabled by default requirement to the source
Browse files Browse the repository at this point in the history
Currently it is quite cumbersome effort to include the source of a
bundle with an installation even though there might be multiple demands,
for example legal reasons or debugging.

This now adds a new greedy, optional requirement that is disabled by a
filter so it is not effective by default but enables an install agent to
specify a property of org.eclipse.update.install.source=true to
include sources of bundles in products whenever available.
  • Loading branch information
laeubi committed Feb 4, 2024
1 parent 7ced201 commit 9d571f9
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,10 @@ public interface IProductDescriptor {
public String[] getIcons(String os);

/**
* Returns a List<BundleInfo> for each bundle that has custom configuration data.
* @return A List<BundleInfo>
* Returns a {@code List<BundleInfo>} for each bundle that has custom
* configuration data.
*
* @return A {@code List<BundleInfo>}
*/
public List<BundleInfo> getBundleInfos();

Expand All @@ -191,8 +193,10 @@ public interface IProductDescriptor {
public String getLicenseText();

/**
* Returns a List<IRepositoryReference> for each update repository used by the product.
* @return A List<IRepositoryReference>
* Returns a {@code List<IRepositoryReference>} for each update repository used
* by the product.
*
* @return A {@code List<IRepositoryReference>}
*/
public List<IRepositoryReference> getRepositoryEntries();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,20 +281,20 @@ public File getLocation() {
}

/**
* Returns the properties found in .product file. Properties
* are located in the <configurations> block of the file
* Returns the properties found in .product file. Properties are located in the
* {@code <configurations>} block of the file
*/
@Override
public Map<String, String> getConfigurationProperties() {
return getConfigurationProperties(null, null);
}

/**
* Returns the properties found in .product file that are valid
* for the specified platform os and architecture. If there is no
* platform os and/or architecture specified, return only the properties
* that are not filtered by the unspecified os and/or arch.
* Properties are located in the <configurations> block of the file
* Returns the properties found in .product file that are valid for the
* specified platform os and architecture. If there is no platform os and/or
* architecture specified, return only the properties that are not filtered by
* the unspecified os and/or arch. Properties are located in the
* {@code <configurations>} block of the file
*/
@Override
public Map<String, String> getConfigurationProperties(String os, String arch) {
Expand Down Expand Up @@ -341,7 +341,8 @@ public Map<String, String> getConfigurationProperties(String os, String arch) {
}

/**
* Returns a List<VersionedName> for each bundle that makes up this product.
* Returns a {@code List<VersionedName>} for each bundle that makes up this
* product.
*/
@Override
public List<IVersionedId> getBundles() {
Expand All @@ -359,17 +360,19 @@ public boolean hasBundles() {
}

/**
* Returns a List<BundleInfo> for each bundle that has custom configuration data
* in the product file.
* @return A List<BundleInfo>
* Returns a {@code List<BundleInfo>} for each bundle that has custom
* configuration data in the product file.
*
* @return A {@code List<BundleInfo>}
*/
@Override
public List<BundleInfo> getBundleInfos() {
return bundleInfos != null ? bundleInfos : Collections.emptyList();
}

/**
* Returns a List<VersionedName> of features that constitute this product.
* Returns a {@code List<VersionedName>} of features that constitute this
* product.
*/
@Override
public List<IVersionedId> getFeatures() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
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.Headers;
import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
Expand All @@ -61,7 +61,7 @@
* bundles or folders of bundles.
*
* This action consults the following types of advice:
* </ul>
* <ul>
* <li>{@link IAdditionalInstallableUnitAdvice }</li>
* <li>{@link IBundleShapeAdvice}</li>
* <li>{@link ICapabilityAdvice}</li>
Expand All @@ -72,6 +72,15 @@
@SuppressWarnings("restriction")
public class BundlesAction extends AbstractPublisherAction {

public static final String FILTER_PROPERTY_INSTALL_SOURCE = "org.eclipse.update.install.source"; //$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
Expand Down Expand Up @@ -235,8 +244,6 @@ protected IInstallableUnit doCreateBundleIU(BundleDescription bd, IArtifactKey k
addRequirement(requirements, requiredCap, rawRequireCapHeader, bd);
}

iu.setRequirements(requirements.toArray(new IRequirement[requirements.size()]));

// Create set of provided capabilities
List<IProvidedCapability> providedCapabilities = new ArrayList<>();

Expand Down Expand Up @@ -276,6 +283,12 @@ protected IInstallableUnit doCreateBundleIU(BundleDescription bd, IArtifactKey k
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
Expand All @@ -294,7 +307,7 @@ protected IInstallableUnit doCreateBundleIU(BundleDescription bd, IArtifactKey k
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
Expand Down Expand Up @@ -840,10 +853,9 @@ public static Dictionary<String, String> basicLoadManifest(File bundleLocation)
manifestStream = new BufferedInputStream(new FileInputStream(manifestFile));
}
}
Dictionary<String, String> manifest = null;
try {
if (manifestStream != null) {
manifest = parseBundleManifestIntoModifyableDictionaryWithCaseInsensitiveKeys(manifestStream);
return parseBundleManifestIntoModifyableDictionaryWithCaseInsensitiveKeys(manifestStream);
}
} finally {
try {
Expand All @@ -854,18 +866,15 @@ public static Dictionary<String, String> basicLoadManifest(File bundleLocation)
}
}

return manifest;
return null;

}

/**
* @return the same result as {@link Headers#parseManifest(InputStream)}, but
* with a modifiable {@link Headers} instance
*/
private static Headers<String, String> parseBundleManifestIntoModifyableDictionaryWithCaseInsensitiveKeys(
private static Dictionary<String, String> parseBundleManifestIntoModifyableDictionaryWithCaseInsensitiveKeys(
InputStream manifestStream) throws IOException, BundleException {
return (Headers<String, String>) ManifestElement.parseBundleManifest(manifestStream,
new Headers<>(10));
CaseInsensitiveDictionaryMap<String, String> map = new CaseInsensitiveDictionaryMap<>(10);
ManifestElement.parseBundleManifest(manifestStream, map);
return map;
}

private static ManifestElement[] parseManifestHeader(String header, Map<String, String> manifest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
package org.eclipse.equinox.p2.publisher.eclipse;

import java.io.File;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.FileUtils;
import org.eclipse.equinox.internal.p2.publisher.eclipse.BrandingIron;
Expand All @@ -32,15 +33,15 @@
import org.eclipse.osgi.service.environment.Constants;

/**
* Given the description of an executable, this action publishes optionally
* Given the description of an executable, this action publishes optionally
* non-destructively brands the executable, publishes the resultant artifacts
* and publishes the required IUs to identify the branded executable, configure
* the executable and set it up as the launcher for a profile.
* <p>
* This action works on one platform configuration only.
* <p>
* This action consults the following types of advice:
* </ul>
* <ul>
* <li>{@link IBrandingAdvice}</li>
* </ul>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
* be actual locations of the features or folders of features.
*/
public class FeaturesAction extends AbstractPublisherAction {
public static final String INSTALL_FEATURES_FILTER = "(org.eclipse.update.install.features=true)"; //$NON-NLS-1$
public static final String FILTER_PROPERTY_INSTALL_FEATURES = "org.eclipse.update.install.features"; //$NON-NLS-1$
public static final String INSTALL_FEATURES_FILTER = String.format("(%s=true)", FILTER_PROPERTY_INSTALL_FEATURES); //$NON-NLS-1$
private static final String UPDATE_FEATURE_APPLICATION_PROP = "org.eclipse.update.feature.application"; //$NON-NLS-1$
private static final String UPDATE_FEATURE_PLUGIN_PROP = "org.eclipse.update.feature.plugin"; //$NON-NLS-1$
private static final String UPDATE_FEATURE_EXCLUSIVE_PROP = "org.eclipse.update.feature.exclusive"; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@

/**
* <p>
* This application generates meta-data and artifact repositories from a set of features and bundles.
* If -source <localdir> parameter is given, it specifies the directory under which to find the features
* and bundles (in the standard "features" and "plugins" sub-directories).
* </p><p>
* Optionally, the -features <csv of file locations> and -bundles <csv of file locations> arguments can
* be specified. If given, these override the defaults derived from a supplied -source parameter.
* This application generates meta-data and artifact repositories from a set of
* features and bundles. If {@code -source <localdir>} parameter is given, it
* specifies the directory under which to find the features and bundles (in the
* standard "features" and "plugins" sub-directories).
* </p>
* <p>
* Optionally, the {@code -features <csv of file locations>} and
* {@code -bundles <csv} of file locations> arguments can be specified. If
* given, these override the defaults derived from a supplied -source parameter.
* </p>
*/
public class FeaturesAndBundlesPublisherApplication extends AbstractPublisherApplication {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private void createRootAdvice() {
info.addAdvice(new RootIUAdvice(list));
}

private Collection<IVersionedId> createInstallModeRootFeatures() {
protected Collection<IVersionedId> createInstallModeRootFeatures() {
Collection<IVersionedId> rootFeatures = listElements(product.getFeatures(IProductDescriptor.ROOT_FEATURES),
".feature.group"); //$NON-NLS-1$
if (!rootFeatures.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,16 @@
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.tools.ant.Task;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.artifact.repository.CompositeArtifactRepository;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository;
import org.eclipse.equinox.internal.p2.publisher.Messages;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.publisher.IPublisherInfo;
import org.eclipse.equinox.p2.publisher.Publisher;
import org.eclipse.equinox.p2.publisher.PublisherInfo;
import org.eclipse.equinox.p2.publisher.*;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.ArtifactKeyQuery;
Expand All @@ -47,10 +41,10 @@ public abstract class AbstractPublishTask extends Task {

/**
* Support nested repository elements that looking something like
* <repo location="file:/foo" metadata="true" artifact="true" /> Both metadata
* and artifact are optional: 1) if neither are set, the repo is used for both
* metadata and artifacts 2) if only one is true, the repo is that type and not
* the other
* {@code <repo location="file:/foo" metadata="true" artifact="true" />} Both
* metadata and artifact are optional: 1) if neither are set, the repo is used
* for both metadata and artifacts 2) if only one is true, the repo is that type
* and not the other
*/
static public class RepoEntry {
private URI repoLocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ private void verifyBundle2() {
verifyRequirement(requirements, TEST2_IU_B_NAMESPACE, TEST2_REQ_B_NAME, TEST2_IU_B_VERSION_RANGE);
verifyRequirement(requirements, TEST2_IU_C_NAMESPACE, TEST2_REQ_C_NAME, TEST2_IU_C_VERSION_RANGE);
verifyRequirement(requirements, OSGI_EE, TEST2_REQ_EE, null, 1, 1, true);
assertEquals(4, requirements.size());
assertEquals(5, requirements.size());

// check provided capabilities
Collection<IProvidedCapability> providedCapabilities = bundleIu.getProvidedCapabilities();
Expand Down Expand Up @@ -365,7 +365,7 @@ private void verifyBundle4() {
1, true);
verifyRequirement(requirements, OSGI, TEST4_REQ_BUNDLE_OPTIONAL_NAME, DEFAULT_VERSION_RANGE, null, 0, 1, false);
verifyRequirement(requirements, OSGI, TEST4_REQ_BUNDLE_OPTGREEDY_NAME, DEFAULT_VERSION_RANGE, null, 0, 1, true);
assertEquals(4, requirements.size());
assertEquals(5, requirements.size());
}

private void verifyBundle5() {
Expand Down Expand Up @@ -492,7 +492,7 @@ public void testDynamicImport() throws Exception {

Collection<IRequirement> requirements = iu.getRequirements();
verifyRequirement(requirements, OSGI_EE, TESTDYN_REQ_EE, null, 1, 1, true);
assertEquals(1, requirements.size());
assertEquals(2, requirements.size());
}

public void testPublishBundlesWhereOneBundleIsInvalid() throws Exception {
Expand Down

0 comments on commit 9d571f9

Please sign in to comment.