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 22, 2023
1 parent 93e210c commit e825d30
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 2 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
@@ -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 @@ -37,6 +37,7 @@
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 Down Expand Up @@ -1084,6 +1085,7 @@ private void resolveWithPlanner(ITargetDefinition target, IProgressMonitor monit
context.setProperty(ProvisioningContext.FOLLOW_REPOSITORY_REFERENCES, Boolean.toString(true));
context.setMetadataRepositories(getMetadataRepositories(target).toArray(URI[]::new));
context.setArtifactRepositories(getArtifactRepositories(target).toArray(URI[]::new));
context.setExtraInstallableUnits(getAdditionalProvisionIUs(target));

IProvisioningPlan plan = planner.getProvisioningPlan(request, context, subMonitor.split(20));
IStatus status = plan.getStatus();
Expand Down Expand Up @@ -1555,6 +1557,30 @@ private Collection<URI> getMetadataRepositories(ITargetDefinition target) throws
return result;
}

private List<IInstallableUnit> getAdditionalProvisionIUs(ITargetDefinition target) throws CoreException {
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;
}
if (container instanceof TargetReferenceBundleContainer targetRefContainer) {
ITargetDefinition referencedTargetDefinition = targetRefContainer.getTargetDefinition();
result.addAll(getAdditionalProvisionIUs(referencedTargetDefinition));
continue;
}
if (!container.isResolved()) {
container.resolve(target, new NullProgressMonitor());
}
InstallableUnitGenerator.generateInstallableUnits(container.getBundles(), container.getFeatures())
.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

0 comments on commit e825d30

Please sign in to comment.