blob: 8eda94414a64ac79708c5f6046605cdb6d8a86c9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 EclipseSource Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* EclipseSource Inc. - initial API and implementation
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 477527
*******************************************************************************/
package org.eclipse.pde.internal.core.target;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.IFileSystem;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetLocation;
import org.eclipse.pde.core.target.NameVersionDescriptor;
import org.eclipse.pde.core.target.TargetBundle;
import org.eclipse.pde.core.target.TargetFeature;
import org.eclipse.pde.internal.core.PDECoreMessages;
/**
* This job exports the bundles and features that make up your target.
*/
public class ExportTargetJob extends Job {
private final URI fDestination;
private boolean fclearDestinationDirectory = true;
private IFileStore featureDir;
private IFileStore pluginDir;
private IFileSystem fileSystem;
private Map<String, NameVersionDescriptor[]> filter;
private final ITargetDefinition fTarget;
public ExportTargetJob(ITargetDefinition target, URI destination, boolean clearDestinationDirectory) {
super("Export Current Target Definition"); //$NON-NLS-1$
fTarget = target;
fDestination = destination;
fclearDestinationDirectory = clearDestinationDirectory;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
constructFilter(fTarget);
ITargetLocation[] containers = fTarget.getTargetLocations();
if (containers == null) {
containers = new ITargetLocation[0];
}
int totalWork = containers.length;
monitor.beginTask(PDECoreMessages.ExportTargetDefinition_task, totalWork);
monitor.subTask(PDECoreMessages.ExportTargetJob_ConfiguringDestination);
setupDestination(monitor);
monitor.subTask(PDECoreMessages.ExportTargetJob_ExportingTargetContents);
for (ITargetLocation targetLocation : containers) {
ITargetLocation container = targetLocation;
container.resolve(fTarget, monitor);
if (!(container instanceof IUBundleContainer)) {
exportContainer(container, fTarget, featureDir, pluginDir, fileSystem, monitor);
}
}
exportProfile(fTarget, fDestination, monitor);
} catch (CoreException e) {
return Status.error("Failed to export the target", e); //$NON-NLS-1$
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
private void constructFilter(ITargetDefinition target) {
NameVersionDescriptor[] included = target.getIncluded();
if (included == null) {
return;
}
filter = new HashMap<>();
for (NameVersionDescriptor inclusion : included) {
NameVersionDescriptor[] versions = filter.get(inclusion.getId());
if (versions == null) {
filter.put(inclusion.getId(), new NameVersionDescriptor[] {inclusion});
} else {
NameVersionDescriptor[] versions2 = new NameVersionDescriptor[versions.length + 1];
System.arraycopy(versions, 0, versions2, 0, versions.length);
versions2[versions.length] = inclusion;
filter.put(inclusion.getId(), versions2);
}
}
}
private void setupDestination(IProgressMonitor monitor) throws CoreException {
fileSystem = EFS.getLocalFileSystem();
if (!fileSystem.canWrite()) {
throw new CoreException(Status.error("Destination directory not writable.")); //$NON-NLS-1$
}
IFileStore destination = fileSystem.getStore(fDestination);
featureDir = destination.getChild("features"); //$NON-NLS-1$ExportTargetJob
pluginDir = destination.getChild("plugins"); //$NON-NLS-1$
if (fclearDestinationDirectory) {
monitor.subTask(PDECoreMessages.ExportTargetDeleteOldData); //Deleting old data...
featureDir.delete(EFS.NONE, null);
pluginDir.delete(EFS.NONE, null);
}
featureDir.mkdir(EFS.NONE, null);
pluginDir.mkdir(EFS.NONE, null);
}
private boolean shouldExport(NameVersionDescriptor descriptor) {
// currently PDE does not selectively include/exclude features
if (filter == null || descriptor.getType().equals(NameVersionDescriptor.TYPE_FEATURE)) {
return true;
}
NameVersionDescriptor[] versions = filter.get(descriptor.getId());
if (versions == null) {
return false;
}
for (NameVersionDescriptor nameVersionDescriptor : versions) {
String version = nameVersionDescriptor.getVersion();
if ((version == null || version.equals(descriptor.getVersion())) && descriptor.getType().equals(nameVersionDescriptor.getType())) {
return true;
}
}
return false;
}
private boolean shouldExport(TargetFeature feature) {
if (filter == null) {
return true;
}
NameVersionDescriptor descriptor = new NameVersionDescriptor(feature.getId(), feature.getVersion(), NameVersionDescriptor.TYPE_FEATURE);
return shouldExport(descriptor);
}
private boolean shouldExport(TargetBundle bundle) {
if (filter == null) {
return true;
}
NameVersionDescriptor descriptor = new NameVersionDescriptor(bundle.getBundleInfo().getSymbolicName(), bundle.getBundleInfo().getVersion(), NameVersionDescriptor.TYPE_PLUGIN);
return shouldExport(descriptor);
}
private boolean shouldExport(IInstallableUnit iu) {
if (filter == null) {
return true;
}
NameVersionDescriptor descriptor = null;
String feature = getCapability(iu, "org.eclipse.update.feature"); //$NON-NLS-1$
if (feature != null) {
descriptor = new NameVersionDescriptor(feature, iu.getVersion().toString(), NameVersionDescriptor.TYPE_FEATURE);
} else if (iu.getId().endsWith(".feature.group")) { //$NON-NLS-1$
descriptor = new NameVersionDescriptor(iu.getId(), iu.getVersion().toString(), NameVersionDescriptor.TYPE_FEATURE);
} else if ("bundle".equalsIgnoreCase(getCapability(iu, "org.eclipse.equinox.p2.eclipse.type"))) { //$NON-NLS-1$ //$NON-NLS-2$
descriptor = new NameVersionDescriptor(iu.getId(), iu.getVersion().toString(), NameVersionDescriptor.TYPE_PLUGIN);
} else if ("source".equalsIgnoreCase(getCapability(iu, "org.eclipse.equinox.p2.eclipse.type"))) { //$NON-NLS-1$ //$NON-NLS-2$
descriptor = new NameVersionDescriptor(iu.getId(), iu.getVersion().toString(), NameVersionDescriptor.TYPE_PLUGIN);
}
// default to true unless we know otherwise. This ensures that random metadata bits
// are moved over to the target as they might be needed in a future provisioning operation.
// We could move only unknown IUs that do NOT have artifacts... Have to think about that.
return descriptor == null ? true : shouldExport(descriptor);
}
private String getCapability(IInstallableUnit iu, String namespace) {
for (IProvidedCapability capability : iu.getProvidedCapabilities()) {
if (capability.getNamespace().equals(namespace)) {
return capability.getName();
}
}
return null;
}
private void exportContainer(ITargetLocation container, ITargetDefinition target, IFileStore featureDir, IFileStore pluginDir, IFileSystem fileSystem, IProgressMonitor monitor) throws CoreException {
TargetFeature[] features = container.getFeatures();
if (features != null) {
monitor.subTask(PDECoreMessages.ExportTargetExportFeatures);
for (TargetFeature feature : features) {
if (shouldExport(feature)) {
String location = feature.getLocation();
if (location != null) {
copy(location, featureDir, fileSystem, monitor);
}
}
}
}
TargetBundle[] bundles = container.getBundles();
if (bundles != null) {
monitor.subTask(PDECoreMessages.ExportTargetExportPlugins);
for (TargetBundle bundle : bundles) {
if (shouldExport(bundle)) {
copy(bundle.getBundleInfo().getLocation().getPath(), pluginDir, fileSystem, monitor);
}
}
}
}
private IStatus copy(String src, IFileStore destinationParent, IFileSystem fileSystem, IProgressMonitor monitor) throws CoreException {
Path srcPath = new Path(src);
IFileStore source = fileSystem.getStore(srcPath);
String elementName = srcPath.segment(srcPath.segmentCount() - 1);
IFileStore destination = destinationParent.getChild(elementName);
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
if (destination.fetchInfo().exists()) {
return Status.OK_STATUS;
}
if (source.fetchInfo().isDirectory()) {
destination.mkdir(EFS.NONE, new NullProgressMonitor());
}
source.copy(destination, EFS.OVERWRITE, subMonitor.split(1));
return Status.OK_STATUS;
}
@SuppressWarnings("restriction")
private org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor createRepoDescriptor(URI location,
String name, String kind) {
org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor result = new org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor();
result.setLocation(location);
result.setKind(kind);
result.setName(name);
if (fclearDestinationDirectory) {
result.setAppend(false);
}
return result;
}
@SuppressWarnings("restriction")
private static final String KIND_METADATA = org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor.KIND_METADATA;
@SuppressWarnings("restriction")
private static final String KIND_ARTIFACT = org.eclipse.equinox.p2.internal.repository.tools.RepositoryDescriptor.KIND_ARTIFACT;
@SuppressWarnings("restriction")
private void exportProfile(ITargetDefinition target, URI destination, IProgressMonitor monitor)
throws CoreException {
var exporter = new org.eclipse.equinox.p2.internal.repository.tools.Repo2Runnable();
exporter.addDestination(createRepoDescriptor(destination, P2TargetUtils.getProfileId(target), KIND_METADATA));
exporter.addDestination(createRepoDescriptor(destination, P2TargetUtils.getProfileId(target), KIND_ARTIFACT));
exporter.addSource(createRepoDescriptor(P2TargetUtils.getBundlePool().getLocation(), null, KIND_ARTIFACT));
IQueryResult<IInstallableUnit> ius = P2TargetUtils.getIUs(target, monitor);
ArrayList<IInstallableUnit> toExport = new ArrayList<>();
for (IInstallableUnit iu : ius) {
if (shouldExport(iu)) {
toExport.add(iu);
}
}
exporter.setSourceIUs(toExport);
exporter.run(monitor);
}
}