blob: b344561d5ab0cffbe3c53062961c832d59f4af92 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.launching.p2utils;
import static org.eclipse.rcptt.launching.p2utils.Q7P2UtilsActivator.PLUGIN_ID;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.internal.p2.artifact.repository.simple.SimpleArtifactRepository;
import org.eclipse.equinox.internal.p2.director.PermissiveSlicer;
import org.eclipse.equinox.internal.p2.repository.Transport;
import org.eclipse.equinox.internal.p2.touchpoint.eclipse.Util;
import org.eclipse.equinox.internal.p2.touchpoint.eclipse.actions.CollectAction;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.internal.repository.mirroring.Mirroring;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryable;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRequest;
import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.rcptt.launching.injection.UpdateSite;
import org.eclipse.rcptt.util.FileUtil;
@SuppressWarnings("restriction")
public class P2Utils {
public static interface ILogMonitor {
void log(String message);
}
/**
* Return PDE target platform sercice.
*
* @return
*/
public static ITargetPlatformService getTargetService() {
Class<ITargetPlatformService> serviceClass = ITargetPlatformService.class;
return getPDECoreService(serviceClass, serviceClass.getName());
}
private static <T> T getPDECoreService(Class<T> serviceClass, String serviceName) {
PDECore pdeCore = PDECore.getDefault();
try {
Method strMethod = pdeCore.getClass().getMethod("acquireService", String.class);
if (strMethod != null) {
return (T) strMethod.invoke(pdeCore, serviceName);
}
} catch (Throwable ex) {
// Q7P2UtilsActivator.log(new Status(Status.ERROR, Q7P2UtilsActivator.PLUGIN_ID,
// ex.getMessage(), ex));
}
try {
Method classMethod = pdeCore.getClass().getMethod("acquireService", Class.class);
if (classMethod != null) {
return (T) classMethod.invoke(pdeCore, serviceClass);
}
} catch (Throwable ex) {
// Q7P2UtilsActivator.log(new Status(Status.ERROR, Q7P2UtilsActivator.PLUGIN_ID,
// ex.getMessage(), ex));
}
return null;
}
/**
* Return P2 metadata repository manager.
*
* @return
* @throws CoreException
*/
public static IMetadataRepositoryManager getRepositoryManager() throws CoreException {
return getRepositoryManager(getProvisioningAgent());
}
public static IProvisioningAgent getProvisioningAgent() {
return getPDECoreService(IProvisioningAgent.class, IProvisioningAgent.SERVICE_NAME);
}
/**
* Return P2 metadata repository manager.
*
* @return
* @throws CoreException
*/
public static IMetadataRepositoryManager getRepositoryManager(IProvisioningAgent agent) throws CoreException {
if (agent == null) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID,
"Failed to locate repository. Can't get service " + IProvisioningAgent.SERVICE_NAME));
}
IMetadataRepositoryManager manager = (IMetadataRepositoryManager) agent
.getService(IMetadataRepositoryManager.SERVICE_NAME);
if (manager == null) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID,
"Failed to locate repository. No metadata repository manager found."));
}
return manager;
}
public static IArtifactRepositoryManager getArtifactRepositoryManager() throws CoreException {
return getArtifactRepositoryManager(getProvisioningAgent());
}
public static IArtifactRepositoryManager getArtifactRepositoryManager(IProvisioningAgent agent)
throws CoreException {
if (agent == null)
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID,
"Failed to locate repository. Can't get service " + IProvisioningAgent.SERVICE_NAME));
IArtifactRepositoryManager manager = (IArtifactRepositoryManager) agent
.getService(IArtifactRepositoryManager.SERVICE_NAME);
if (manager == null) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID,
"Failed to locate repository. No metadata repository manager found."));
}
return manager;
}
public static IMetadataRepository safeLoadRepository(URI uri, IProgressMonitor monitor, IProvisioningAgent agent)
throws CoreException {
try {
// Be sure to read freash repository each time
IMetadataRepositoryManager rm = getRepositoryManager(agent);
rm.removeRepository(uri);
try {
rm.refreshRepository(uri, monitor);
} catch (ProvisionException e) {
// Ignore, this is ok, need to clean badRepo variable.
}
return rm.loadRepository(uri, monitor);
} catch (RuntimeException e) {
if (e instanceof OperationCanceledException || monitor.isCanceled()) {
throw new CoreException(
new Status(IStatus.CANCEL, Q7P2UtilsActivator.PLUGIN_ID, "Repository load cancelled", e));
} else {
throw e;
}
}
}
public static IArtifactRepository safeLoadArtifactRepository(URI uri, IProgressMonitor monitor,
IProvisioningAgent agent) {
try {
// Be sure to read freash repository each time
IArtifactRepositoryManager rm = getArtifactRepositoryManager(agent);
rm.removeRepository(uri);
try {
rm.refreshRepository(uri, monitor);
} catch (ProvisionException e) {
// Ignore, this is ok, need to clean badRepo variable.
}
return rm.loadRepository(uri, monitor);
} catch (Throwable e) {
if (e instanceof OperationCanceledException || monitor.isCanceled()) {
return null;
}
Q7P2UtilsActivator.getDefault().log(e);
}
return null;
}
public static Set<String> mapUnitsToId(Set<IInstallableUnit> availableUnits) {
Set<String> unitIDs = new HashSet<String>();
for (IInstallableUnit u : availableUnits) {
unitIDs.add(u.getId());
}
return unitIDs;
}
public static List<IQuery<IInstallableUnit>> mapUnitsToQuery(Set<String> units) {
List<IQuery<IInstallableUnit>> queries = new ArrayList<IQuery<IInstallableUnit>>();
for (String id : units) {
queries.add(QueryUtil.createIUQuery(id));
}
return queries;
}
public static List<IQuery<IInstallableUnit>> mapUnitsToCategoryQuery(Collection<IInstallableUnit> units) {
List<IQuery<IInstallableUnit>> queries = new ArrayList<IQuery<IInstallableUnit>>();
for (IInstallableUnit unit : units) {
Collection<IRequirement> requirements = unit.getRequirements();
for (IRequirement req : requirements) {
queries.add(QueryUtil.createMatchQuery(req.getMatches(), new Object[] {}));
}
}
return queries;
}
public static IQuery<IInstallableUnit> createQuery(UpdateSite site) {
IQuery<IInstallableUnit> finalQuery = null;
if (site.isAllUnits()) {
finalQuery = QueryUtil.ALL_UNITS;
} else {
List<IQuery<IInstallableUnit>> items = P2Utils.mapUnitsToQuery(new HashSet<String>(site.getUnits()));
finalQuery = QueryUtil.createLatestQuery(QueryUtil.createCompoundQuery(items, false));
}
return finalQuery;
}
public static IStatus validateBundle(File file) {
if (!file.exists()) {
return new Status(IStatus.ERROR, PLUGIN_ID, "File " + file + " does not exist");
}
if (file.isDirectory()) {
return Status.OK_STATUS;
}
/**
* Validate file consistency check if this is valid zip archive if it is jar
*/
if (file.getName().toLowerCase().endsWith(".jar")) {
BufferedInputStream stream = null;
ZipInputStream zin = null;
try {
stream = new BufferedInputStream(new FileInputStream(file));
zin = new ZipInputStream(stream);
Set<String> names = new HashSet<String>();
while (true) {
ZipEntry entry = zin.getNextEntry();
if (entry == null) {
if (names.size() == 0) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Empty ZIP archive " + file);
}
return Status.OK_STATUS;
}
names.add(entry.getName());
}
} catch (Throwable e) {
return new Status(IStatus.ERROR, PLUGIN_ID, "Failed to check " + file, e);
} finally {
FileUtil.safeClose(zin);
FileUtil.safeClose(stream);
}
}
return Status.OK_STATUS;
}
public static void installUnits(IProgressMonitor monitor, IArtifactRepository artifactRepository,
IFileArtifactRepository filesRepository, List<IInstallableUnit> toInstall, int installTryCount,
ILogMonitor logMonitor, boolean useRaw, IProvisioningAgent agent) throws CoreException {
if (logMonitor != null) {
logMonitor.log("Downloading artifacts to: " + filesRepository.getLocation().toString());
}
filesRepository.setProperty(SimpleArtifactRepository.PROP_FORCE_THREADING, "true");
while (toInstall.size() > 0) {
List<IArtifactKey> keys = new ArrayList<IArtifactKey>();
for (IInstallableUnit unit : toInstall) {
keys.addAll(unit.getArtifacts());
}
List<IArtifactRequest> requests = new ArrayList<IArtifactRequest>();
if (useRaw) {
rawMirror(artifactRepository, filesRepository, logMonitor, agent, keys);
} else {
// Collect requests
for (IInstallableUnit unit : toInstall) {
Collection<IArtifactKey> toDownload = unit.getArtifacts();
for (IArtifactKey key : toDownload) {
Map<String, String> repositoryProperties = CollectAction
.createArtifactDescriptorProperties(unit);
requests.add(Util.getArtifactRepositoryManager(agent).createMirrorRequest(key, filesRepository,
null, repositoryProperties));
}
}
if (requests.size() == 0) {
break;// All is OK.
}
artifactRepository.getArtifacts(
(IArtifactRequest[]) requests.toArray(new IArtifactRequest[requests.size()]), monitor);
}
MultiStatus rv = new MultiStatus(PLUGIN_ID, 0, "Failed to install bundles", null);
// Check and validate installed units
List<IInstallableUnit> installedOK = new ArrayList<IInstallableUnit>();
for (IInstallableUnit unit : toInstall) {
Collection<IArtifactKey> toDownload = unit.getArtifacts();
if (toDownload == null || toDownload.size() == 0) {
// This is most probable feature.
installedOK.add(unit);
continue;
}
for (IArtifactKey key : toDownload) {
File file = filesRepository.getArtifactFile(key);
if (file != null && file.exists()) {
IStatus result = P2Utils.validateBundle(file);
if (result.isOK()) {
installedOK.add(unit);
continue;
} else {
rv.add(result);
}
}
// Remove key, since it is not valid
filesRepository.removeDescriptor(key, monitor);
}
}
toInstall.removeAll(installedOK);
if (toInstall.size() == 0) {
return;
}
installTryCount--;
if (installTryCount < 0) {
throw new CoreException(rv);
}
if (logMonitor != null) {
logMonitor.log("Artifacts left on iteration: " + toInstall.size() + " retrying: " + installTryCount
+ "delay: 5 seconds");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new CoreException(Status.CANCEL_STATUS);
}
}
}
}
private static void rawMirror(IArtifactRepository artifactRepository, IFileArtifactRepository filesRepository,
ILogMonitor logMonitor, IProvisioningAgent agent, List<IArtifactKey> keys) {
Mirroring mirror = new Mirroring(artifactRepository, filesRepository, true);
mirror.setCompare(false);
mirror.setComparatorId(null);
mirror.setBaseline(null);
mirror.setValidate(false);
mirror.setCompareExclusions(null);
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()]));
}
IStatus result = mirror.run(false, false);
if (result != null && !result.isOK() && logMonitor != null) {
logMonitor.log("Mirroring is failed: " + result.getMessage());
}
}
public static IQuery<IInstallableUnit> createContainmentQuery(Set<IInstallableUnit> availableUnits) {
return QueryUtil.createCompoundQuery(mapUnitsToCategoryQuery(availableUnits), false);
}
public static void expandFeatures(IProgressMonitor monitor, IMetadataRepository repository,
Set<IInstallableUnit> availableUnits) {
PermissiveSlicer slicer = new PermissiveSlicer(repository, new Hashtable<String, String>(), false, // include
// optional
// depenencies
true, // is everything greedy
true, // forceFilterTo,
true, // considerStrictDependencyOnly,
false); // slicingOptions.followOnlyFilteredRequirements());
IQueryable<IInstallableUnit> slice = slicer
.slice(availableUnits.toArray(new IInstallableUnit[availableUnits.size()]), monitor);
availableUnits.addAll(slice.query(QueryUtil.ALL_UNITS, monitor).toSet());
}
}