| /******************************************************************************* |
| * Copyright (c) 2009, 2013 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 |
| * Sonatype, Inc. - ongoing development |
| * Red Hat, Inc. - fragment creation |
| *******************************************************************************/ |
| package org.eclipse.equinox.p2.internal.repository.tools; |
| |
| import java.io.*; |
| import java.net.URI; |
| 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.frameworkadmin.BundleInfo; |
| import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; |
| import org.eclipse.equinox.internal.p2.engine.*; |
| import org.eclipse.equinox.internal.p2.engine.phases.Collect; |
| import org.eclipse.equinox.p2.core.IProvisioningAgent; |
| import org.eclipse.equinox.p2.core.ProvisionException; |
| import org.eclipse.equinox.p2.engine.*; |
| import org.eclipse.equinox.p2.engine.spi.ProvisioningAction; |
| import org.eclipse.equinox.p2.metadata.*; |
| import org.eclipse.equinox.p2.query.IQueryResult; |
| import org.eclipse.equinox.p2.query.QueryUtil; |
| import org.eclipse.equinox.p2.repository.artifact.*; |
| import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; |
| import org.eclipse.equinox.simpleconfigurator.manipulator.SimpleConfiguratorManipulator; |
| |
| /** |
| * 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$ |
| private static final String PARM_PROFILE = "profile"; //$NON-NLS-1$ |
| |
| private boolean createFragments; |
| private boolean flagAsRunnable = false; |
| |
| protected class CollectNativesAction extends ProvisioningAction { |
| public IStatus execute(Map<String, Object> parameters) { |
| InstallableUnitOperand operand = (InstallableUnitOperand) parameters.get(PARM_OPERAND); |
| IInstallableUnit installableUnit = operand.second(); |
| |
| IArtifactRepositoryManager manager = getArtifactRepositoryManager(); |
| Collection<IArtifactKey> toDownload = installableUnit.getArtifacts(); |
| if (toDownload == null) |
| return Status.OK_STATUS; |
| |
| @SuppressWarnings("unchecked") |
| List<IArtifactRequest> artifactRequests = (List<IArtifactRequest>) parameters.get(NATIVE_ARTIFACTS); |
| |
| IProfile profile = (IProfile) parameters.get(PARM_PROFILE); |
| String statsParameter = null; |
| if (profile != null) |
| statsParameter = profile.getProperty(IProfile.PROP_STATS_PARAMETERS); |
| |
| for (IArtifactKey keyToDownload : toDownload) { |
| IArtifactRequest request = manager.createMirrorRequest(keyToDownload, destinationArtifactRepository, null, null, statsParameter); |
| artifactRequests.add(request); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| public IStatus undo(Map<String, Object> parameters) { |
| // nothing to do for now |
| return Status.OK_STATUS; |
| } |
| } |
| |
| protected class CollectNativesPhase extends InstallableUnitPhase { |
| public CollectNativesPhase(int weight) { |
| super(NATIVE_ARTIFACTS, weight); |
| } |
| |
| protected List<ProvisioningAction> getActions(InstallableUnitOperand operand) { |
| IInstallableUnit unit = operand.second(); |
| if (unit.getTouchpointType().getId().equals(NATIVE_TYPE)) { |
| return Collections.<ProvisioningAction> singletonList(new CollectNativesAction()); |
| } |
| return null; |
| } |
| |
| protected IStatus initializePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) { |
| parameters.put(NATIVE_ARTIFACTS, new ArrayList<Object>()); |
| return null; |
| } |
| |
| protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters) { |
| @SuppressWarnings("unchecked") |
| List<IArtifactRequest> artifactRequests = (List<IArtifactRequest>) parameters.get(NATIVE_ARTIFACTS); |
| ProvisioningContext context = (ProvisioningContext) parameters.get(PARM_CONTEXT); |
| IProvisioningAgent agent = (IProvisioningAgent) parameters.get(PARM_AGENT); |
| DownloadManager dm = new DownloadManager(context, agent); |
| for (IArtifactRequest request : artifactRequests) { |
| dm.add(request); |
| } |
| 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<IInstallableUnit> processedIUs = new ArrayList<IInstallableUnit>(); |
| |
| /* |
| * 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)); |
| |
| // call the engine with only the "collect" phase so all we do is download |
| IProfile profile = createProfile(); |
| try { |
| IEngine engine = (IEngine) agent.getService(IEngine.SERVICE_NAME); |
| if (engine == null) |
| throw new ProvisionException(Messages.exception_noEngineService); |
| ProvisioningContext context = new ProvisioningContext(agent); |
| context.setMetadataRepositories(getRepositories(true)); |
| context.setArtifactRepositories(getRepositories(false)); |
| IProvisioningPlan plan = engine.createPlan(profile, context); |
| for (Iterator<IInstallableUnit> iterator = processedIUs.iterator(); iterator.hasNext();) { |
| plan.addInstallableUnit(iterator.next()); |
| } |
| 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)); |
| |
| setRunnableProperty(destinationArtifactRepository); |
| // return the resulting status |
| |
| if (createFragments) { |
| File parentDir = new File(destinationArtifactRepository.getLocation().toString().substring(5)); |
| File pluginsDir = new File(parentDir, "plugins"); |
| File fragmentInfo = new File(parentDir, "fragment.info"); |
| HashSet<BundleInfo> bundles = new HashSet<BundleInfo>(); |
| try { |
| for (Iterator<IInstallableUnit> iterator = processedIUs.iterator(); iterator.hasNext();) { |
| IInstallableUnit unit = iterator.next(); |
| if (unit.getId().equals("a.jre")) |
| continue; |
| Collection<IProvidedCapability> providedCapabilities = unit.getProvidedCapabilities(); |
| for (IProvidedCapability cap : providedCapabilities) { |
| if ("org.eclipse.equinox.p2.eclipse.type".equals(cap.getNamespace())) { |
| if ("bundle".equals(cap.getName())) { |
| File candidate = new File(pluginsDir, unit.getId() + "_" + unit.getVersion()); |
| if (candidate.exists()) { |
| bundles.add(new BundleInfo(unit.getId(), unit.getVersion().toString(), candidate.toURI(), 4, false)); |
| } |
| candidate = new File(pluginsDir, unit.getId() + "_" + unit.getVersion() + ".jar"); |
| if (candidate.exists()) { |
| bundles.add(new BundleInfo(unit.getId(), unit.getVersion().toString(), candidate.toURI(), 4, false)); |
| } |
| break; |
| } |
| } |
| } |
| } |
| SimpleConfiguratorManipulator simpleManipulator = (SimpleConfiguratorManipulator) ServiceHelper.getService(Activator.getBundleContext(), SimpleConfiguratorManipulator.class.getName()); |
| simpleManipulator.saveConfiguration(bundles.toArray(new BundleInfo[0]), fragmentInfo, parentDir.toURI()); |
| } catch (FileNotFoundException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } catch (IOException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| return result; |
| } finally { |
| // cleanup by removing the temporary profile and unloading the repos which were new |
| removeProfile(profile); |
| finalizeRepositories(); |
| } |
| } |
| |
| static class Writer extends ProfileWriter { |
| |
| public Writer(OutputStream output) throws IOException { |
| super(output, new ProcessingInstruction[] {ProcessingInstruction.makeTargetVersionInstruction(PROFILE_TARGET, ProfileXMLConstants.CURRENT_VERSION)}); |
| } |
| } |
| |
| private void setRunnableProperty(IArtifactRepository destinationArtifactRepository) { |
| if (flagAsRunnable) |
| destinationArtifactRepository.setProperty(IArtifactRepository.PROP_RUNNABLE, Boolean.TRUE.toString(), new NullProgressMonitor()); |
| } |
| |
| protected URI[] getRepositories(boolean metadata) { |
| List<URI> repos = new ArrayList<URI>(); |
| for (RepositoryDescriptor repo : sourceRepositories) { |
| if (metadata ? repo.isMetadata() : repo.isArtifact()) |
| repos.add(repo.getRepoLocation()); |
| } |
| return repos.toArray(new URI[repos.size()]); |
| } |
| |
| 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); |
| |
| Iterator<IInstallableUnit> itor = getAllIUs(getCompositeMetadataRepository(), monitor).iterator(); |
| while (itor.hasNext()) |
| processedIUs.add(itor.next()); |
| |
| 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(processedIUs); |
| } |
| |
| /* |
| * Return a collector over all the IUs contained in the given repository. |
| */ |
| private IQueryResult<IInstallableUnit> getAllIUs(IMetadataRepository repository, IProgressMonitor monitor) { |
| SubMonitor progress = SubMonitor.convert(monitor, 2); |
| try { |
| return repository.query(QueryUtil.createIUAnyQuery(), 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<String, String> properties = new HashMap<String, String>(); |
| 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]; |
| String arg = null; |
| if (i != args.length - 1 && !args[i + 1].startsWith("-")) { //$NON-NLS-1$ |
| 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); |
| } |
| |
| if (option.equalsIgnoreCase("-flagAsRunnable")) { //$NON-NLS-1$ |
| setFlagAsRunnable(true); |
| } |
| |
| if (option.equalsIgnoreCase("-createFragments")) { //$NON-NLS-1$ |
| setCreateFragments(true); |
| } |
| } |
| } |
| |
| public void setFlagAsRunnable(boolean runnable) { |
| flagAsRunnable = runnable; |
| } |
| |
| /* |
| * 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 |
| } |
| |
| public void setCreateFragments(boolean createFragments) { |
| this.createFragments = createFragments; |
| |
| } |
| } |