/******************************************************************************* * Copyright (c) 2008, 2010 Code 9 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: * Code 9 - initial API and implementation * IBM - ongoing development ******************************************************************************/ package org.eclipse.equinox.p2.publisher; import java.net.URI; import java.util.Collection; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.core.helpers.Tracing; import org.eclipse.equinox.internal.p2.publisher.Activator; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.repository.*; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; public class Publisher { static final public String PUBLISH_PACK_FILES_AS_SIBLINGS = "publishPackFilesAsSiblings"; //$NON-NLS-1$ private static final long SERVICE_TIMEOUT = 5000; private IPublisherInfo info; private IPublisherResult results; /** * Returns a metadata repository that corresponds to the given settings. If a repository at the * given location already exists, it is updated with the settings and returned. If no repository * is found then a new Simple repository is created, configured and returned * @param agent the provisioning agent to use when creating the repository * @param location the URL location of the repository * @param name the name of the repository * @param append whether or not the repository should appended or cleared * @param compress whether or not to compress the repository index * @return the discovered or created repository * @throws ProvisionException */ public static IMetadataRepository createMetadataRepository(IProvisioningAgent agent, URI location, String name, boolean append, boolean compress) throws ProvisionException { try { IMetadataRepository result = loadMetadataRepository(agent, location, true, true); if (result != null && result.isModifiable()) { result.setProperty(IRepository.PROP_COMPRESSED, compress ? "true" : "false"); //$NON-NLS-1$//$NON-NLS-2$ if (!append) result.removeAll(); return result; } } catch (ProvisionException e) { //fall through and create a new repository } // the given repo location is not an existing repo so we have to create something IMetadataRepositoryManager manager = getService(agent, IMetadataRepositoryManager.SERVICE_NAME); String repositoryName = name == null ? location + " - metadata" : name; //$NON-NLS-1$ IMetadataRepository result = manager.createRepository(location, repositoryName, IMetadataRepositoryManager.TYPE_SIMPLE_REPOSITORY, null); if (result != null) { manager.removeRepository(result.getLocation()); result.setProperty(IRepository.PROP_COMPRESSED, compress ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$ return result; } // I don't think we can really get here, but just in case, we better throw a provisioning exception String msg = org.eclipse.equinox.internal.p2.metadata.repository.Messages.repoMan_internalError; throw new ProvisionException(new Status(IStatus.ERROR, Activator.ID, ProvisionException.INTERNAL_ERROR, msg, null)); } /** * Load a metadata repository from the given location. * @param location the URI location of the repository * @param modifiable whether to ask the manager for a modifiable repository * @param removeFromManager remove the loaded repository from the manager if it wasn't already loaded * @return the loaded repository * @throws ProvisionException */ public static IMetadataRepository loadMetadataRepository(IProvisioningAgent agent, URI location, boolean modifiable, boolean removeFromManager) throws ProvisionException { IMetadataRepositoryManager manager = getService(agent, IMetadataRepositoryManager.SERVICE_NAME); boolean existing = manager.contains(location); IMetadataRepository result = manager.loadRepository(location, modifiable ? IRepositoryManager.REPOSITORY_HINT_MODIFIABLE : 0, null); if (!existing && removeFromManager) manager.removeRepository(location); return result; } /** * Returns an artifact repository that corresponds to the given settings. If a repository at the * given location already exists, it is updated with the settings and returned. If no repository * is found then a new Simple repository is created, configured and returned * @param agent the provisioning agent to use when creating the repository * @param location the URL location of the repository * @param name the name of the repository * @param compress whether or not to compress the repository index * @param reusePackedFiles whether or not to include discovered Pack200 files in the repository * @return the discovered or created repository * @throws ProvisionException */ public static IArtifactRepository createArtifactRepository(IProvisioningAgent agent, URI location, String name, boolean compress, boolean reusePackedFiles) throws ProvisionException { try { IArtifactRepository result = loadArtifactRepository(agent, location, true, true); if (result != null && result.isModifiable()) { result.setProperty(IRepository.PROP_COMPRESSED, compress ? "true" : "false"); //$NON-NLS-1$//$NON-NLS-2$ if (reusePackedFiles) result.setProperty(PUBLISH_PACK_FILES_AS_SIBLINGS, "true"); //$NON-NLS-1$ return result; } } catch (ProvisionException e) { //fall through and create a new repository } IArtifactRepositoryManager manager = getService(agent, IArtifactRepositoryManager.SERVICE_NAME); String repositoryName = name != null ? name : location + " - artifacts"; //$NON-NLS-1$ IArtifactRepository result = manager.createRepository(location, repositoryName, IArtifactRepositoryManager.TYPE_SIMPLE_REPOSITORY, null); if (result != null) { manager.removeRepository(result.getLocation()); if (reusePackedFiles) result.setProperty(PUBLISH_PACK_FILES_AS_SIBLINGS, "true"); //$NON-NLS-1$ result.setProperty(IRepository.PROP_COMPRESSED, compress ? "true" : "false"); //$NON-NLS-1$//$NON-NLS-2$ return result; } // I don't think we can really get here, but just in case, we better throw a provisioning exception String msg = org.eclipse.equinox.internal.p2.artifact.repository.Messages.repoMan_internalError; throw new ProvisionException(new Status(IStatus.ERROR, Activator.ID, ProvisionException.INTERNAL_ERROR, msg, null)); } /** * Load an artifact repository from the given location. * @param location the URI location of the repository * @param modifiable whether to ask the manager for a modifiable repository * @param removeFromManager remove the loaded repository from the manager if it wasn't already loaded * @return the loaded repository * @throws ProvisionException */ public static IArtifactRepository loadArtifactRepository(IProvisioningAgent agent, URI location, boolean modifiable, boolean removeFromManager) throws ProvisionException { IArtifactRepositoryManager manager = getService(agent, IArtifactRepositoryManager.SERVICE_NAME); boolean existing = manager.contains(location); IArtifactRepository result = manager.loadRepository(location, modifiable ? IRepositoryManager.REPOSITORY_HINT_MODIFIABLE : 0, null); if (!existing && removeFromManager) manager.removeRepository(location); return result; } public Publisher(IPublisherInfo info) { this.info = info; results = new PublisherResult(); } /** * Obtains a service from the agent, waiting for a reasonable timeout period * if the service is not yet available. This method never returns <code>null</code>; * an exception is thrown if the service could not be obtained. * * @param <T> The type of the service to return * @param agent The agent to obtain the service from * @param serviceName The name of the service to obtain * @return The service instance */ @SuppressWarnings("unchecked") protected static <T> T getService(IProvisioningAgent agent, String serviceName) { T service = (T) agent.getService(serviceName); if (service != null) return service; long start = System.currentTimeMillis(); do { try { Thread.sleep(100); } catch (InterruptedException e) { //ignore and keep waiting } service = (T) agent.getService(serviceName); if (service != null) return service; } while ((System.currentTimeMillis() - start) < SERVICE_TIMEOUT); //could not obtain the service throw new IllegalStateException("Unable to obtain required service: " + serviceName); //$NON-NLS-1$ } public Publisher(IPublisherInfo info, IPublisherResult results) { this.info = info; this.results = results; } class ArtifactProcess implements IRunnableWithProgress { private final IPublisherAction[] actions; private final IPublisherInfo info; private IStatus result = null; public ArtifactProcess(IPublisherAction[] actions, IPublisherInfo info) { this.info = info; this.actions = actions; } public void run(IProgressMonitor monitor) { MultiStatus finalStatus = new MultiStatus("this", 0, "publishing result", null); //$NON-NLS-1$//$NON-NLS-2$ for (int i = 0; i < actions.length; i++) { if (monitor.isCanceled()) { result = Status.CANCEL_STATUS; return; } IStatus status = actions[i].perform(info, results, monitor); finalStatus.merge(status); monitor.worked(1); } result = finalStatus; } public IStatus getStatus() { return result; } } public IStatus publish(IPublisherAction[] actions, IProgressMonitor monitor) { if (monitor == null) monitor = new NullProgressMonitor(); SubMonitor sub = SubMonitor.convert(monitor, actions.length); if (Tracing.DEBUG_PUBLISHING) Tracing.debug("Invoking publisher"); //$NON-NLS-1$ try { ArtifactProcess artifactProcess = new ArtifactProcess(actions, info); IStatus finalStatus = null; if (info.getArtifactRepository() != null) { finalStatus = info.getArtifactRepository().executeBatch(artifactProcess, sub); if (finalStatus.isOK()) // If the batch process didn't report any errors, then // Use the status from our actions finalStatus = artifactProcess.getStatus(); } else { artifactProcess.run(sub); finalStatus = artifactProcess.getStatus(); } if (Tracing.DEBUG_PUBLISHING) Tracing.debug("Publishing complete. Result=" + finalStatus); //$NON-NLS-1$ if (!finalStatus.isOK()) return finalStatus; } finally { sub.done(); } // if there were no errors, publish all the ius. IMetadataRepository metadataRepository = info.getMetadataRepository(); if (metadataRepository != null) { Collection<IInstallableUnit> ius = results.getIUs(null, null); metadataRepository.addInstallableUnits(ius); } return Status.OK_STATUS; } }