| /******************************************************************************* |
| * Copyright (c) 2009, 2011 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 java.io.File; |
| 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.internal.p2.core.helpers.LogHelper; |
| import org.eclipse.equinox.internal.p2.director.PermissiveSlicer; |
| import org.eclipse.equinox.internal.p2.repository.Transport; |
| import org.eclipse.equinox.internal.p2.repository.helpers.RepositoryHelper; |
| import org.eclipse.equinox.p2.core.ProvisionException; |
| import org.eclipse.equinox.p2.engine.*; |
| import org.eclipse.equinox.p2.internal.repository.mirroring.*; |
| import org.eclipse.equinox.p2.metadata.*; |
| import org.eclipse.equinox.p2.planner.IPlanner; |
| import org.eclipse.equinox.p2.planner.IProfileChangeRequest; |
| import org.eclipse.equinox.p2.query.*; |
| import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor; |
| import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; |
| import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; |
| import org.eclipse.osgi.util.NLS; |
| |
| public class MirrorApplication extends AbstractApplication implements IApplication, IExecutableExtension { |
| private static final String LOG_ROOT = "p2.mirror"; //$NON-NLS-1$ |
| private static final String MIRROR_MODE = "metadataOrArtifacts"; //$NON-NLS-1$ |
| |
| protected SlicingOptions slicingOptions = new SlicingOptions(); |
| |
| private URI baseline; |
| private String comparatorID; |
| private IQuery<IArtifactDescriptor> compareExclusions = null; |
| private boolean compare = false; |
| private boolean failOnError = true; |
| private boolean raw = true; |
| private boolean verbose = false; |
| private boolean validate = false; |
| private boolean mirrorReferences = true; |
| private String metadataOrArtifacts = null; |
| private String[] rootIUs = null; |
| |
| private File mirrorLogFile; // file to log mirror output to (optional) |
| private File comparatorLogFile; // file to comparator output to (optional) |
| private IArtifactMirrorLog mirrorLog; |
| private IArtifactMirrorLog comparatorLog; |
| |
| /** |
| * Convert a list of tokens into an array. The list separator has to be |
| * specified. |
| */ |
| public static String[] getArrayArgsFromString(String list, String separator) { |
| if (list == null || list.trim().equals("")) //$NON-NLS-1$ |
| return new String[0]; |
| List<String> result = new ArrayList<String>(); |
| for (StringTokenizer tokens = new StringTokenizer(list, separator); tokens.hasMoreTokens();) { |
| String token = tokens.nextToken().trim(); |
| if (!token.equals("")) { //$NON-NLS-1$ |
| if ((token.indexOf('[') >= 0 || token.indexOf('(') >= 0) && tokens.hasMoreTokens()) |
| result.add(token + separator + tokens.nextToken()); |
| else |
| result.add(token); |
| } |
| } |
| return result.toArray(new String[result.size()]); |
| } |
| |
| public Object start(IApplicationContext context) throws Exception { |
| Map<?, ?> args = context.getArguments(); |
| initializeFromArguments((String[]) args.get(IApplicationContext.APPLICATION_ARGS)); |
| run(null); |
| return IApplication.EXIT_OK; |
| } |
| |
| public void stop() { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| /* |
| * The old "org.eclipse.equinox.p2.artifact.repository.mirrorApplication" application only does artifacts |
| * Similary, "org.eclipse.equinox.p2.metadata.repository.mirrorApplication" only does metadata |
| */ |
| public void setInitializationData(IConfigurationElement config, String propertyName, Object data) { |
| if (data instanceof Map<?, ?> && ((Map<?, ?>) data).containsKey(MIRROR_MODE)) { |
| metadataOrArtifacts = (String) ((Map<?, ?>) data).get(MIRROR_MODE); |
| } |
| } |
| |
| public void initializeFromArguments(String[] args) throws Exception { |
| if (args == null) |
| return; |
| |
| File comparatorLogLocation = null; |
| File mirrorLogLocation = null; |
| |
| RepositoryDescriptor destination = new RepositoryDescriptor(); |
| RepositoryDescriptor sourceRepo = new RepositoryDescriptor(); |
| if (metadataOrArtifacts != null) { |
| destination.setKind(metadataOrArtifacts); |
| sourceRepo.setKind(metadataOrArtifacts); |
| } |
| |
| addDestination(destination); |
| addSource(sourceRepo); |
| |
| for (int i = 0; i < args.length; i++) { |
| // check for args without parameters (i.e., a flag arg) |
| if (args[i].equalsIgnoreCase("-raw")) //$NON-NLS-1$ |
| raw = true; |
| else if (args[i].equalsIgnoreCase("-ignoreErrors")) //$NON-NLS-1$ |
| failOnError = false; |
| else if (args[i].equalsIgnoreCase("-verbose")) //$NON-NLS-1$ |
| verbose = true; |
| else if (args[i].equalsIgnoreCase("-compare")) //$NON-NLS-1$ |
| compare = true; |
| else if (args[i].equalsIgnoreCase("-validate")) //$NON-NLS-1$ |
| validate = true; |
| else if (args[i].equalsIgnoreCase("-references")) //$NON-NLS-1$ |
| mirrorReferences = true; |
| |
| // check for args with parameters. If we are at the last argument or |
| // if the next one has a '-' as the first character, then we can't have |
| // an arg with a param so continue. |
| if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$ |
| continue; |
| |
| String arg = args[++i]; |
| |
| if (args[i - 1].equalsIgnoreCase("-comparator")) //$NON-NLS-1$ |
| comparatorID = arg; |
| else if (args[i - 1].equalsIgnoreCase("-comparatorLog")) //$NON-NLS-1$ |
| comparatorLogLocation = new File(arg); |
| else if (args[i - 1].equalsIgnoreCase("-destinationName")) //$NON-NLS-1$ |
| destination.setName(arg); |
| else if (args[i - 1].equalsIgnoreCase("-writeMode")) { //$NON-NLS-1$ |
| if (args[i].equalsIgnoreCase("clean")) //$NON-NLS-1$ |
| destination.setAppend(false); |
| } else if (args[i - 1].equalsIgnoreCase("-log")) { //$NON-NLS-1$ |
| mirrorLogLocation = new File(arg); |
| } else if (args[i - 1].equalsIgnoreCase("-roots")) { //$NON-NLS-1$ |
| rootIUs = getArrayArgsFromString(arg, ","); //$NON-NLS-1$ |
| } else { |
| try { |
| if (args[i - 1].equalsIgnoreCase("-source")) { //$NON-NLS-1$ |
| URI uri = RepositoryHelper.localRepoURIHelper(URIUtil.fromString(arg)); |
| sourceRepo.setLocation(uri); |
| destination.setFormat(uri); |
| } else if (args[i - 1].equalsIgnoreCase("-destination")) //$NON-NLS-1$ |
| destination.setLocation(RepositoryHelper.localRepoURIHelper(URIUtil.fromString(arg))); |
| else if (args[i - 1].equalsIgnoreCase("-compareAgainst")) { //$NON-NLS-1$ |
| baseline = RepositoryHelper.localRepoURIHelper(URIUtil.fromString(arg)); |
| compare = true; |
| } |
| } catch (URISyntaxException e) { |
| throw new IllegalArgumentException(NLS.bind(Messages.ProcessRepo_location_not_url, arg)); |
| } |
| } |
| } |
| |
| // Create logs |
| if (mirrorLogLocation != null) |
| mirrorLog = getLog(mirrorLogLocation, "p2.artifact.mirror"); //$NON-NLS-1$ |
| if (comparatorLogLocation != null && comparatorID != null) |
| comparatorLog = getLog(comparatorLogLocation, comparatorID); |
| } |
| |
| public IStatus run(IProgressMonitor monitor) throws ProvisionException { |
| IStatus mirrorStatus = Status.OK_STATUS; |
| try { |
| initializeRepos(new NullProgressMonitor()); |
| initializeLogs(); |
| validate(); |
| initializeIUs(); |
| IQueryable<IInstallableUnit> slice = slice(new NullProgressMonitor()); |
| if (destinationArtifactRepository != null) { |
| mirrorStatus = mirrorArtifacts(slice, new NullProgressMonitor()); |
| if (failOnError && mirrorStatus.getSeverity() == IStatus.ERROR) |
| return mirrorStatus; |
| } |
| if (destinationMetadataRepository != null) |
| mirrorMetadata(slice, new NullProgressMonitor()); |
| } finally { |
| finalizeRepositories(); |
| finalizeLogs(); |
| } |
| if (mirrorStatus.isOK()) |
| return Status.OK_STATUS; |
| return mirrorStatus; |
| } |
| |
| private IStatus mirrorArtifacts(IQueryable<IInstallableUnit> slice, IProgressMonitor monitor) { |
| // Obtain ArtifactKeys from IUs |
| IQueryResult<IInstallableUnit> ius = slice.query(QueryUtil.createIUAnyQuery(), monitor); |
| ArrayList<IArtifactKey> keys = new ArrayList<IArtifactKey>(); |
| for (Iterator<IInstallableUnit> iterator = ius.iterator(); iterator.hasNext();) { |
| IInstallableUnit iu = iterator.next(); |
| keys.addAll(iu.getArtifacts()); |
| } |
| |
| Mirroring mirror = new Mirroring(getCompositeArtifactRepository(), destinationArtifactRepository, raw); |
| mirror.setCompare(compare); |
| mirror.setComparatorId(comparatorID); |
| mirror.setBaseline(initializeBaseline()); |
| mirror.setValidate(validate); |
| mirror.setCompareExclusions(compareExclusions); |
| mirror.setTransport((Transport) agent.getService(Transport.SERVICE_NAME)); |
| |
| // If IUs have been specified then only they should be mirrored, otherwise mirror everything. |
| if (keys.size() > 0) |
| mirror.setArtifactKeys(keys.toArray(new IArtifactKey[keys.size()])); |
| |
| if (comparatorLog != null) |
| mirror.setComparatorLog(comparatorLog); |
| |
| IStatus result = mirror.run(failOnError, verbose); |
| |
| if (mirrorLog != null) |
| mirrorLog.log(result); |
| else |
| LogHelper.log(result); |
| return result; |
| } |
| |
| private IArtifactRepository initializeBaseline() { |
| if (baseline == null) |
| return null; |
| try { |
| return addRepository(getArtifactRepositoryManager(), baseline, 0, null); |
| } catch (ProvisionException e) { |
| if (mirrorLog != null && e.getStatus() != null) |
| mirrorLog.log(e.getStatus()); |
| return null; |
| } |
| } |
| |
| private void mirrorMetadata(IQueryable<IInstallableUnit> slice, IProgressMonitor monitor) { |
| IQueryResult<IInstallableUnit> allIUs = slice.query(QueryUtil.createIUAnyQuery(), monitor); |
| destinationMetadataRepository.addInstallableUnits(allIUs.toUnmodifiableSet()); |
| if (mirrorReferences) |
| destinationMetadataRepository.addReferences(getCompositeMetadataRepository().getReferences()); |
| } |
| |
| /* |
| * 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 (sourceRepositories.isEmpty()) |
| throw new ProvisionException(Messages.MirrorApplication_set_source_repositories); |
| if (!hasArtifactSources() && destinationArtifactRepository != null) |
| throw new ProvisionException(Messages.MirrorApplication_artifactDestinationNoSource); |
| if (!hasMetadataSources() && destinationMetadataRepository != null) |
| throw new ProvisionException(Messages.MirrorApplication_metadataDestinationNoSource); |
| } |
| |
| /* |
| * If no IUs have been specified we want to mirror them all |
| */ |
| private void initializeIUs() throws ProvisionException { |
| IMetadataRepository metadataRepo = getCompositeMetadataRepository(); |
| |
| if (rootIUs != null) { |
| sourceIUs = new ArrayList<IInstallableUnit>(); |
| for (int i = 0; i < rootIUs.length; i++) { |
| String[] segments = getArrayArgsFromString(rootIUs[i], "/"); //$NON-NLS-1$ |
| VersionRange range = segments.length > 1 ? new VersionRange(segments[1]) : null; |
| Iterator<IInstallableUnit> queryResult = metadataRepo.query(QueryUtil.createIUQuery(segments[0], range), null).iterator(); |
| while (queryResult.hasNext()) |
| sourceIUs.add(queryResult.next()); |
| } |
| } else if (sourceIUs == null || sourceIUs.isEmpty()) { |
| sourceIUs = new ArrayList<IInstallableUnit>(); |
| Iterator<IInstallableUnit> queryResult = metadataRepo.query(QueryUtil.createIUAnyQuery(), null).iterator(); |
| while (queryResult.hasNext()) |
| sourceIUs.add(queryResult.next()); |
| /* old metadata mirroring app did not throw an exception here */ |
| if (sourceIUs.size() == 0 && destinationMetadataRepository != null && metadataOrArtifacts == null) |
| throw new ProvisionException(Messages.MirrorApplication_no_IUs); |
| } |
| } |
| |
| /* |
| * Initialize logs, if applicable |
| */ |
| private void initializeLogs() { |
| if (compare && comparatorLogFile != null) |
| comparatorLog = getLog(comparatorLogFile, comparatorID); |
| if (mirrorLog == null && mirrorLogFile != null) |
| mirrorLog = getLog(mirrorLogFile, LOG_ROOT); |
| } |
| |
| /* |
| * Finalize logs, if applicable |
| */ |
| private void finalizeLogs() { |
| if (comparatorLog != null) |
| comparatorLog.close(); |
| if (mirrorLog != null) |
| mirrorLog.close(); |
| } |
| |
| /* |
| * Get the log for a location |
| */ |
| private IArtifactMirrorLog getLog(File location, String root) { |
| String absolutePath = location.getAbsolutePath(); |
| if (absolutePath.toLowerCase().endsWith(".xml")) //$NON-NLS-1$ |
| return new XMLMirrorLog(absolutePath, 0, root); |
| return new FileMirrorLog(absolutePath, 0, root); |
| } |
| |
| private IQueryable<IInstallableUnit> performResolution(IProgressMonitor monitor) throws ProvisionException { |
| IProfileRegistry registry = Activator.getProfileRegistry(); |
| String profileId = "MirrorApplication-" + System.currentTimeMillis(); //$NON-NLS-1$ |
| IProfile profile = registry.addProfile(profileId, slicingOptions.getFilter()); |
| IPlanner planner = (IPlanner) Activator.getAgent().getService(IPlanner.SERVICE_NAME); |
| if (planner == null) |
| throw new IllegalStateException(); |
| IProfileChangeRequest pcr = planner.createChangeRequest(profile); |
| pcr.addAll(sourceIUs); |
| IProvisioningPlan plan = planner.getProvisioningPlan(pcr, null, monitor); |
| registry.removeProfile(profileId); |
| @SuppressWarnings("unchecked") |
| IQueryable<IInstallableUnit>[] arr = new IQueryable[plan.getInstallerPlan() == null ? 1 : 2]; |
| arr[0] = plan.getAdditions(); |
| if (plan.getInstallerPlan() != null) |
| arr[1] = plan.getInstallerPlan().getAdditions(); |
| return new CompoundQueryable<IInstallableUnit>(arr); |
| } |
| |
| private IQueryable<IInstallableUnit> slice(IProgressMonitor monitor) throws ProvisionException { |
| if (slicingOptions == null) |
| slicingOptions = new SlicingOptions(); |
| if (slicingOptions.getInstallTimeLikeResolution()) |
| return performResolution(monitor); |
| |
| PermissiveSlicer slicer = new PermissiveSlicer(getCompositeMetadataRepository(), slicingOptions.getFilter(), slicingOptions.includeOptionalDependencies(), slicingOptions.isEverythingGreedy(), slicingOptions.forceFilterTo(), slicingOptions.considerStrictDependencyOnly(), slicingOptions.followOnlyFilteredRequirements()); |
| IQueryable<IInstallableUnit> slice = slicer.slice(sourceIUs.toArray(new IInstallableUnit[sourceIUs.size()]), monitor); |
| |
| if (slice != null && slicingOptions.latestVersionOnly()) { |
| IQueryResult<IInstallableUnit> queryResult = slice.query(QueryUtil.createLatestIUQuery(), monitor); |
| slice = queryResult; |
| } |
| if (slicer.getStatus().getSeverity() != IStatus.OK && mirrorLog != null) { |
| mirrorLog.log(slicer.getStatus()); |
| } |
| if (slice == null) { |
| throw new ProvisionException(slicer.getStatus()); |
| } |
| return slice; |
| } |
| |
| public void setSlicingOptions(SlicingOptions options) { |
| slicingOptions = options; |
| } |
| |
| /* |
| * Set the location of the baseline repository. (used in comparison) |
| */ |
| public void setBaseline(URI baseline) { |
| this.baseline = baseline; |
| compare = true; |
| } |
| |
| /* |
| * Set the identifier of the comparator to use. |
| */ |
| public void setComparatorID(String value) { |
| comparatorID = value; |
| compare = true; |
| } |
| |
| /* |
| * Set whether or not the application should be calling a comparator when mirroring. |
| */ |
| public void setCompare(boolean value) { |
| compare = value; |
| } |
| |
| /* |
| * Set whether or not we should ignore errors when running the mirror application. |
| */ |
| public void setIgnoreErrors(boolean value) { |
| failOnError = !value; |
| } |
| |
| /* |
| * Set whether or not the the artifacts are raw. |
| */ |
| public void setRaw(boolean value) { |
| raw = value; |
| } |
| |
| /* |
| * Set whether or not the mirror application should be run in verbose mode. |
| */ |
| public void setVerbose(boolean value) { |
| verbose = value; |
| } |
| |
| /* |
| * Set the location of the log for comparator output |
| */ |
| public void setComparatorLog(File comparatorLog) { |
| this.comparatorLogFile = comparatorLog; |
| } |
| |
| /* |
| * Set the location of the log for mirroring. |
| */ |
| public void setLog(File mirrorLog) { |
| this.mirrorLogFile = mirrorLog; |
| } |
| |
| /* |
| * Set the ArtifactMirror log |
| */ |
| public void setLog(IArtifactMirrorLog log) { |
| mirrorLog = log; |
| } |
| |
| /* |
| * Set if the artifact mirror should be validated |
| */ |
| public void setValidate(boolean value) { |
| validate = value; |
| } |
| |
| /* |
| * Set if references should be mirrored |
| */ |
| public void setReferences(boolean flag) { |
| mirrorReferences = flag; |
| } |
| |
| public void setComparatorExclusions(IQuery<IArtifactDescriptor> exclusions) { |
| compareExclusions = exclusions; |
| } |
| } |