blob: 49eeb0cab7379a2121c818f01a366d60c732f75e [file] [log] [blame]
/*******************************************************************************
* 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;
}
}