blob: 3a54dec5018ffbe418830388bcf5c02dae172b8e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.p2.internal.repository.tools;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import java.net.URISyntaxException;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.p2.engine.DownloadManager;
import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException;
import org.eclipse.equinox.internal.provisional.p2.engine.*;
import org.eclipse.equinox.internal.provisional.p2.engine.phases.Collect;
import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.Collector;
import org.eclipse.equinox.internal.provisional.p2.metadata.query.InstallableUnitQuery;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IEngine;
import org.eclipse.equinox.p2.engine.IProvisioningPlan;
import org.eclipse.equinox.p2.engine.spi.ProvisioningAction;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRequest;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
/**
* The transformer takes an existing p2 repository (local or remote), iterates over
* its list of IUs, and fetches all of the corresponding artifacts to a user-specified location.
* Once fetched, the artifacts will be in "runnable" form... that is directory-based bundles will be
* extracted into folders and packed JAR files will be un-packed.
*
* @since 1.0
*/
public class Repo2Runnable extends AbstractApplication implements IApplication {
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$
protected class CollectNativesAction extends ProvisioningAction {
public IStatus execute(Map parameters) {
InstallableUnitOperand operand = (InstallableUnitOperand) parameters.get(PARM_OPERAND);
IInstallableUnit installableUnit = operand.second();
IArtifactRepositoryManager manager = getArtifactRepositoryManager();
IArtifactKey[] toDownload = installableUnit.getArtifacts();
if (toDownload == null)
return Status.OK_STATUS;
List artifactRequests = (List) parameters.get(NATIVE_ARTIFACTS);
for (int i = 0; i < toDownload.length; i++) {
IArtifactRequest request = manager.createMirrorRequest(toDownload[i], destinationArtifactRepository, null, null);
artifactRequests.add(request);
}
return Status.OK_STATUS;
}
public IStatus undo(Map parameters) {
// nothing to do for now
return Status.OK_STATUS;
}
}
protected class CollectNativesPhase extends InstallableUnitPhase {
public CollectNativesPhase(int weight) {
super(NATIVE_ARTIFACTS, weight);
}
protected ProvisioningAction[] getActions(InstallableUnitOperand operand) {
IInstallableUnit unit = operand.second();
if (unit.getTouchpointType().getId().equals(NATIVE_TYPE)) {
return new ProvisioningAction[] {new CollectNativesAction()};
}
return null;
}
protected IStatus initializePhase(IProgressMonitor monitor, IProfile profile, Map parameters) {
parameters.put(NATIVE_ARTIFACTS, new ArrayList());
return null;
}
protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map parameters) {
List artifactRequests = (List) parameters.get(NATIVE_ARTIFACTS);
ProvisioningContext context = (ProvisioningContext) parameters.get(PARM_CONTEXT);
IProvisioningAgent agent = (IProvisioningAgent) parameters.get(PARM_AGENT);
IArtifactRepositoryManager repositoryManager = (IArtifactRepositoryManager) agent.getService(IArtifactRepositoryManager.SERVICE_NAME);
DownloadManager dm = new DownloadManager(context, repositoryManager);
for (Iterator it = artifactRequests.iterator(); it.hasNext();) {
dm.add((IArtifactRequest) it.next());
}
return dm.start(monitor);
}
}
// the list of IUs that we actually transformed... could have come from the repo
// or have been user-specified.
private Collection processedIUs = new ArrayList();
/*
* Perform the transformation.
*/
public IStatus run(IProgressMonitor monitor) throws ProvisionException {
SubMonitor progress = SubMonitor.convert(monitor, 5);
initializeRepos(progress);
// ensure all the right parameters are set
validate();
// figure out which IUs we need to process
collectIUs(progress.newChild(1));
// create the operands from the list of IUs
InstallableUnitOperand[] operands = new InstallableUnitOperand[processedIUs.size()];
int i = 0;
for (Iterator iter = processedIUs.iterator(); iter.hasNext();)
operands[i++] = new InstallableUnitOperand(null, (IInstallableUnit) iter.next());
// call the engine with only the "collect" phase so all we do is download
IProfile profile = createProfile();
try {
ProvisioningContext context = new ProvisioningContext();
IEngine engine = (IEngine) ServiceHelper.getService(Activator.getBundleContext(), IEngine.SERVICE_NAME);
if (engine == null)
throw new ProvisionException(Messages.exception_noEngineService);
IProvisioningPlan plan = engine.createCustomPlan(profile, operands, context);
IStatus result = engine.perform(plan, getPhaseSet(), progress.newChild(1));
PhaseSet nativeSet = getNativePhase();
if (nativeSet != null)
engine.perform(plan, nativeSet, progress.newChild(1));
// publish the metadata to a destination - if requested
publishMetadata(progress.newChild(1));
// return the resulting status
return result;
} finally {
// cleanup by removing the temporary profile and unloading the repos which were new
removeProfile(profile);
finalizeRepositories();
}
}
protected PhaseSet getPhaseSet() {
return new PhaseSet(new Phase[] {new Collect(100)}) { /* nothing to override */};
}
protected PhaseSet getNativePhase() {
return new PhaseSet(new Phase[] {new CollectNativesPhase(100)}) { /*nothing to override */};
}
/*
* Figure out exactly which IUs we have to process.
*/
private void collectIUs(IProgressMonitor monitor) throws ProvisionException {
// if the user told us exactly which IUs to process, then just set it and return.
if (sourceIUs != null && !sourceIUs.isEmpty()) {
processedIUs = sourceIUs;
return;
}
// get all IUs from the repos
if (!hasMetadataSources())
throw new ProvisionException(Messages.exception_needIUsOrNonEmptyRepo);
processedIUs.addAll(getAllIUs(getCompositeMetadataRepository(), monitor).toCollection());
if (processedIUs.isEmpty())
throw new ProvisionException(Messages.exception_needIUsOrNonEmptyRepo);
}
/*
* If there is a destination metadata repository set, then add all our transformed
* IUs to it.
*/
private void publishMetadata(IProgressMonitor monitor) {
// publishing the metadata is optional
if (destinationMetadataRepository == null)
return;
destinationMetadataRepository.addInstallableUnits((IInstallableUnit[]) processedIUs.toArray(new IInstallableUnit[processedIUs.size()]));
}
/*
* Return a collector over all the IUs contained in the given repository.
*/
private Collector getAllIUs(IMetadataRepository repository, IProgressMonitor monitor) {
SubMonitor progress = SubMonitor.convert(monitor, 2);
try {
return repository.query(InstallableUnitQuery.ANY, new Collector(), progress.newChild(1));
} finally {
progress.done();
}
}
/*
* Remove the given profile from the profile registry.
*/
private void removeProfile(IProfile profile) throws ProvisionException {
IProfileRegistry registry = Activator.getProfileRegistry();
registry.removeProfile(profile.getProfileId());
}
/*
* Create and return a new profile.
*/
private IProfile createProfile() throws ProvisionException {
Map properties = new Properties();
properties.put(IProfile.PROP_CACHE, URIUtil.toFile(destinationArtifactRepository.getLocation()).getAbsolutePath());
properties.put(IProfile.PROP_INSTALL_FOLDER, URIUtil.toFile(destinationArtifactRepository.getLocation()).getAbsolutePath());
IProfileRegistry registry = Activator.getProfileRegistry();
return registry.addProfile(System.currentTimeMillis() + "-" + Math.random(), properties); //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
public Object start(IApplicationContext context) throws Exception {
String[] args = (String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS);
processCommandLineArgs(args);
// perform the transformation
run(null);
return IApplication.EXIT_OK;
}
/*
* Iterate over the command-line arguments and prepare the transformer for processing.
*/
private void processCommandLineArgs(String[] args) throws URISyntaxException {
if (args == null)
return;
for (int i = 0; i < args.length; i++) {
String option = args[i];
if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$
continue;
String arg = args[++i];
if (option.equalsIgnoreCase("-source")) { //$NON-NLS-1$
RepositoryDescriptor source = new RepositoryDescriptor();
source.setLocation(URIUtil.fromString(arg));
addSource(source);
}
if (option.equalsIgnoreCase("-destination")) { //$NON-NLS-1$
RepositoryDescriptor destination = new RepositoryDescriptor();
destination.setLocation(URIUtil.fromString(arg));
addDestination(destination);
}
}
}
/*
* Ensure all mandatory parameters have been set. Throw an exception if there
* are any missing. We don't require the user to specify the artifact repository here,
* we will default to the ones already registered in the manager. (callers are free
* to add more if they wish)
*/
private void validate() throws ProvisionException {
if (!hasMetadataSources() && sourceIUs == null)
throw new ProvisionException(Messages.exception_needIUsOrNonEmptyRepo);
if (destinationArtifactRepository == null)
throw new ProvisionException(Messages.exception_needDestinationRepo);
}
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
// nothing to do
}
}