Skip to content

Commit

Permalink
Consider other locations when resolving IUs from updatesites
Browse files Browse the repository at this point in the history
Currently the IULocation can only consider units from other locations if
these are also of type IU location but other target types might be able
to supply items in a way not know to the IULocation.

This adds the necessary infrastructure to support this usecase by using
the adapter pattern.

Fix #207
  • Loading branch information
laeubi committed Oct 9, 2023
1 parent bcf2c51 commit 66a5c24
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 10 deletions.
3 changes: 3 additions & 0 deletions ui/org.eclipse.pde.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ Import-Package: aQute.bnd.build;version="[4.4.0,5.0.0)",
aQute.bnd.service;version="[4.7.0,5.0.0)",
aQute.bnd.version;version="[2.2.0,3.0.0)",
aQute.service.reporter;version="[1.2.0,2.0.0)",
org.eclipse.equinox.internal.p2.publisher.eclipse,
org.eclipse.equinox.p2.publisher,
org.eclipse.equinox.p2.publisher.eclipse,
org.osgi.service.repository;version="[1.1.0,2.0.0)",
org.osgi.util.promise;version="[1.3.0,2.0.0)"
Require-Bundle:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2017 IBM Corporation and others.
* Copyright (c) 2009, 2023 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
* Christoph Läubrich - supply the manifest as a string if requested
*******************************************************************************/
package org.eclipse.pde.core.target;

Expand All @@ -18,6 +19,8 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
Expand Down Expand Up @@ -171,7 +174,22 @@ private void initialize(File file) throws CoreException {
}
Map<String, String> manifest = ManifestUtils.loadManifest(file);
try {
fInfo = new BundleInfo(file.toURI());
fInfo = new BundleInfo(file.toURI()) {
private String manifestString;

@Override
public String getManifest() {
if (manifestString == null) {
try {
StringWriter writer = new StringWriter();
ManifestUtils.writeManifest(manifest, writer);
manifestString = writer.toString();
} catch (IOException e) {
}
}
return manifestString;
}
};
// Attempt to retrieve additional bundle information from the manifest
String header = manifest.get(Constants.BUNDLE_SYMBOLICNAME);
if (header != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitQueryable;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.TargetBundle;
Expand All @@ -34,7 +38,7 @@
*
* @since 3.5
*/
public class DirectoryBundleContainer extends AbstractBundleContainer {
public class DirectoryBundleContainer extends AbstractBundleContainer implements IInstallableUnitQueryable {

/**
* Constant describing the type of bundle container
Expand Down Expand Up @@ -173,4 +177,12 @@ public void reload() {
clearResolutionStatus();
}

@Override
public IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) {
if (fBundles == null || fFeatures == null) {
resolve(null, monitor);
}
return query.perform(InstallableUnitGenerator.generateInstallableUnits(fBundles, fFeatures).iterator());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitQueryable;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetLocation;
Expand All @@ -41,7 +45,7 @@
*
* @since 3.5
*/
public class FeatureBundleContainer extends AbstractBundleContainer {
public class FeatureBundleContainer extends AbstractBundleContainer implements IInstallableUnitQueryable {

/**
* Constant describing the type of bundle container
Expand Down Expand Up @@ -239,4 +243,12 @@ public String[] getVMArguments() {
public void reload() {
clearResolutionStatus();
}

@Override
public IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) {
if (fBundles == null || fFeatures == null) {
resolve(null, monitor);
}
return query.perform(InstallableUnitGenerator.generateInstallableUnits(fBundles, fFeatures).iterator());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*******************************************************************************
* Copyright (c) 2023 Christoph Läubrich and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.core.target;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.stream.Stream;

import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.internal.p2.publisher.eclipse.FeatureManifestParser;
import org.eclipse.equinox.internal.p2.publisher.eclipse.FeatureParser;
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.PublisherResult;
import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction;
import org.eclipse.equinox.p2.publisher.eclipse.Feature;
import org.eclipse.equinox.p2.publisher.eclipse.FeaturesAction;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.pde.core.IModel;
import org.eclipse.pde.core.target.TargetBundle;
import org.eclipse.pde.core.target.TargetFeature;
import org.eclipse.pde.internal.core.ifeature.IFeature;
import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
import org.xml.sax.SAXException;

/**
* Class to generate {@link IInstallableUnit}s from target objects
*/
@SuppressWarnings("restriction")
public class InstallableUnitGenerator {

public static Stream<IInstallableUnit> generateInstallableUnits(TargetBundle[] bundles, TargetFeature[] features) {
return Stream.concat(generateInstallableUnits(bundles), generateInstallableUnits(features));
}

public static Stream<IInstallableUnit> generateInstallableUnits(TargetBundle[] bundles) {
if (bundles == null || bundles.length == 0) {
return Stream.empty();
}
return Arrays.stream(bundles).flatMap(InstallableUnitGenerator::generateInstallableUnits);
}

public static Stream<IInstallableUnit> generateInstallableUnits(TargetBundle targetBundle) {
BundleInfo bundleInfo = targetBundle.getBundleInfo();
if (bundleInfo != null) {
String manifest = bundleInfo.getManifest();
if (manifest != null) {
try {
Manifest parsed = new Manifest(new ByteArrayInputStream(manifest.getBytes(StandardCharsets.UTF_8)));
Attributes mainAttributes = parsed.getMainAttributes();
CaseInsensitiveDictionaryMap<String, String> headers = new CaseInsensitiveDictionaryMap<>(
mainAttributes.size());
Set<Entry<Object, Object>> entrySet = mainAttributes.entrySet();
for (Entry<Object, Object> entry : entrySet) {
headers.put(entry.getKey().toString(), entry.getValue().toString());
}
PublisherInfo publisherInfo = new PublisherInfo();
publisherInfo.setArtifactOptions(IPublisherInfo.A_INDEX);
BundleDescription bundleDescription = BundlesAction.createBundleDescription(headers, null);
IInstallableUnit iu = BundlesAction.createBundleIU(bundleDescription,
BundlesAction.createBundleArtifactKey(bundleDescription.getSymbolicName(),
bundleDescription.getVersion().toString()),
publisherInfo);
return Stream.of(iu);
} catch (IOException e) {
// can't use it then...
}
}
}
return Stream.empty();
}

public static Stream<IInstallableUnit> generateInstallableUnits(TargetFeature[] features) {
if (features == null || features.length == 0) {
return Stream.empty();
}
return Arrays.stream(features).flatMap(InstallableUnitGenerator::generateInstallableUnits);
}

public static Stream<IInstallableUnit> generateInstallableUnits(TargetFeature targetFeature) {
String location = targetFeature.getLocation();
if (location != null) {
Feature feature = new FeatureParser().parse(new File(location));
if (feature != null) {
feature.setLocation(location);
return generateInstallableUnits(feature);
}
}
IModel model = targetFeature.getFeatureModel();
if (model instanceof IFeatureModel featureModel) {
IFeature feature = featureModel.getFeature();
if (feature != null) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
feature.write("", printWriter); //$NON-NLS-1$
printWriter.flush();
try {
generateInstallableUnits(new FeatureManifestParser().parse(
new ByteArrayInputStream(stringWriter.toString().getBytes(StandardCharsets.UTF_8)),
new URL("file:/dummy")));//$NON-NLS-1$
} catch (SAXException | IOException e) {
// can't use it then...
}
}
}
return Stream.empty();
}

private static Stream<IInstallableUnit> generateInstallableUnits(Feature feature) {
PublisherInfo publisherInfo = new PublisherInfo();
publisherInfo.setArtifactOptions(IPublisherInfo.A_INDEX);
FeaturesAction action = new FeaturesAction(new Feature[] { feature }) {
@Override
protected void publishFeatureArtifacts(Feature feature, IInstallableUnit featureIU,
IPublisherInfo publisherInfo) {
// so not call super as we don't wan't to copy anything --> Bug
// in P2 with IPublisherInfo.A_INDEX option
}
};
PublisherResult results = new PublisherResult();
action.perform(publisherInfo, results, null);
return results.query(QueryUtil.ALL_UNITS, null).stream();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.runtime.Adapters;
import org.eclipse.core.runtime.CoreException;
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.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
Expand All @@ -59,6 +61,7 @@
import org.eclipse.equinox.p2.engine.spi.ProvisioningAction;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitQueryable;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.MetadataFactory;
Expand Down Expand Up @@ -1084,6 +1087,7 @@ private void resolveWithPlanner(ITargetDefinition target, IProgressMonitor monit
context.setProperty(ProvisioningContext.FOLLOW_REPOSITORY_REFERENCES, Boolean.toString(true));
context.setMetadataRepositories(getMetadataRepositories(target));
context.setArtifactRepositories(getArtifactRepositories(target));
context.setExtraInstallableUnits(getAdditionalProvisionIUs(target));

IProvisioningPlan plan = planner.getProvisioningPlan(request, context, subMonitor.split(20));
IStatus status = plan.getStatus();
Expand Down Expand Up @@ -1547,6 +1551,24 @@ private URI[] getMetadataRepositories(ITargetDefinition target) throws CoreExcep
return result.toArray(new URI[result.size()]);
}

private List<IInstallableUnit> getAdditionalProvisionIUs(ITargetDefinition target) {
List<IInstallableUnit> result = new ArrayList<>();
ITargetLocation[] containers = target.getTargetLocations();
if (containers != null) {
for (ITargetLocation container : containers) {
if (container instanceof IUBundleContainer) {
// this is already handled by getMetadataRepositories(..)
continue;
}
IInstallableUnitQueryable queryable = Adapters.adapt(container, IInstallableUnitQueryable.class);
if (queryable != null) {
queryable.query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).forEach(result::add);
}
}
}
return result;
}

private static final String NATIVE_ARTIFACTS = "nativeArtifacts"; //$NON-NLS-1$
private static final String NATIVE_TYPE = "org.eclipse.equinox.p2.native"; //$NON-NLS-1$
private static final String PARM_OPERAND = "operand"; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitQueryable;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.TargetBundle;
Expand All @@ -47,7 +51,7 @@
*
* @since 3.5
*/
public class ProfileBundleContainer extends AbstractBundleContainer {
public class ProfileBundleContainer extends AbstractBundleContainer implements IInstallableUnitQueryable {

// The following constants are duplicated from org.eclipse.equinox.internal.p2.core.Activator
private static final String CONFIG_INI = "config.ini"; //$NON-NLS-1$
Expand Down Expand Up @@ -418,4 +422,12 @@ public void reload() {
clearResolutionStatus();
}

@Override
public IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) {
if (fBundles == null || fFeatures == null) {
resolve(null, monitor);
}
return query.perform(InstallableUnitGenerator.generateInstallableUnits(fBundles, fFeatures).iterator());
}

}
Loading

0 comments on commit 66a5c24

Please sign in to comment.