blob: d163af04792dd1ac15b39b1217ba88d6e103ff50 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Cloudsmith - https://bugs.eclipse.org/bugs/show_bug.cgi?id=226401
* EclipseSource - ongoing development
* Sonatype, Inc. - ongoing development
* Pascal Rapicault - Support for bundled macosx 431116
* Red Hat, Inc. - support repositories passed via fragments (see bug 378329).Bug 460967
* SAP AG - list formatting (bug 423538)
* Todor Boev - Software AG
*******************************************************************************/
package org.eclipse.equinox.internal.p2.director.app;
import static org.eclipse.core.runtime.IStatus.*;
import static org.eclipse.equinox.internal.p2.director.app.Activator.ID;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.security.cert.Certificate;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
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.ServiceHelper;
import org.eclipse.equinox.internal.p2.core.helpers.StringHelper;
import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
import org.eclipse.equinox.internal.p2.engine.EngineActivator;
import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus;
import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener;
import org.eclipse.equinox.internal.provisional.p2.director.IDirector;
import org.eclipse.equinox.internal.provisional.p2.director.PlanExecutionHelper;
import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent;
import org.eclipse.equinox.p2.core.*;
import org.eclipse.equinox.p2.engine.*;
import org.eclipse.equinox.p2.engine.query.UserVisibleRootQuery;
import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
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.IRepository;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.osgi.service.environment.EnvironmentInfo;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
public class DirectorApplication implements IApplication, ProvisioningListener {
public static class AvoidTrustPromptService extends UIServices {
@Override
public AuthenticationInfo getUsernamePassword(String location) {
return null;
}
@Override
public AuthenticationInfo getUsernamePassword(String location, AuthenticationInfo previousInfo) {
return null;
}
@Override
public TrustInfo getTrustInfo(Certificate[][] untrustedChains, String[] unsignedDetail) {
final Certificate[] trusted;
if (untrustedChains == null) {
trusted = null;
} else {
trusted = new Certificate[untrustedChains.length];
for (int i = 0; i < untrustedChains.length; i++) {
trusted[i] = untrustedChains[i][0];
}
}
return new TrustInfo(trusted, false, true);
}
}
class LocationQueryable implements IQueryable<IInstallableUnit> {
private URI location;
public LocationQueryable(URI location) {
this.location = location;
Assert.isNotNull(location);
}
@Override
public IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor) {
return getInstallableUnits(location, query, monitor);
}
}
private static class CommandLineOption {
final String[] identifiers;
private final String optionSyntaxString;
private final String helpString;
CommandLineOption(String[] identifiers, String optionSyntaxString, String helpString) {
this.identifiers = identifiers;
this.optionSyntaxString = optionSyntaxString;
this.helpString = helpString;
}
boolean isOption(String opt) {
int idx = identifiers.length;
while (--idx >= 0)
if (identifiers[idx].equalsIgnoreCase(opt))
return true;
return false;
}
void appendHelp(PrintStream out) {
out.print(identifiers[0]);
for (int idx = 1; idx < identifiers.length; ++idx) {
out.print(" | "); //$NON-NLS-1$
out.print(identifiers[idx]);
}
if (optionSyntaxString != null) {
out.print(' ');
out.print(optionSyntaxString);
}
out.println();
out.print(" "); //$NON-NLS-1$
out.println(helpString);
}
}
private static final CommandLineOption OPTION_HELP = new CommandLineOption(new String[] {"-help", "-h", "-?"}, null, Messages.Help_Prints_this_command_line_help); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final CommandLineOption OPTION_LIST = new CommandLineOption(new String[] {"-list", "-l"}, Messages.Help_lb_lt_comma_separated_list_gt_rb, Messages.Help_List_all_IUs_found_in_repos); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_LIST_FORMAT = new CommandLineOption(new String[] {"-listFormat", "-lf"}, Messages.Help_lt_list_format_gt, Messages.Help_formats_the_IU_list); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_LIST_INSTALLED = new CommandLineOption(new String[] {"-listInstalledRoots", "-lir"}, null, Messages.Help_List_installed_roots); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_INSTALL_IU = new CommandLineOption(new String[] {"-installIU", "-installIUs", "-i"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_Installs_the_listed_IUs); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final CommandLineOption OPTION_UNINSTALL_IU = new CommandLineOption(new String[] {"-uninstallIU", "-uninstallIUs", "-u"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_Uninstalls_the_listed_IUs); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final CommandLineOption OPTION_REVERT = new CommandLineOption(new String[] {"-revert"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_Revert_to_previous_state); //$NON-NLS-1$
private static final CommandLineOption OPTION_DESTINATION = new CommandLineOption(new String[] {"-destination", "-d"}, Messages.Help_lt_path_gt, Messages.Help_The_folder_in_which_the_targetd_product_is_located); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_METADATAREPOS = new CommandLineOption(new String[] {"-metadatarepository", "metadatarepositories", "-m"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_A_list_of_URLs_denoting_metadata_repositories); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final CommandLineOption OPTION_ARTIFACTREPOS = new CommandLineOption(new String[] {"-artifactrepository", "artifactrepositories", "-a"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_A_list_of_URLs_denoting_artifact_repositories); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final CommandLineOption OPTION_REPOSITORIES = new CommandLineOption(new String[] {"-repository", "repositories", "-r"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_A_list_of_URLs_denoting_colocated_repositories); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
private static final CommandLineOption OPTION_VERIFY_ONLY = new CommandLineOption(new String[] {"-verifyOnly"}, null, Messages.Help_Only_verify_dont_install); //$NON-NLS-1$
private static final CommandLineOption OPTION_PROFILE = new CommandLineOption(new String[] {"-profile", "-p"}, Messages.Help_lt_name_gt, Messages.Help_Defines_what_profile_to_use_for_the_actions); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_FLAVOR = new CommandLineOption(new String[] {"-flavor", "-f"}, Messages.Help_lt_name_gt, Messages.Help_Defines_flavor_to_use_for_created_profile); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_SHARED = new CommandLineOption(new String[] {"-shared", "-s"}, Messages.Help_lb_lt_path_gt_rb, Messages.Help_Use_a_shared_location_for_the_install); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_BUNDLEPOOL = new CommandLineOption(new String[] {"-bundlepool", "-b"}, Messages.Help_lt_path_gt, Messages.Help_The_location_where_the_plugins_and_features_will_be_stored); //$NON-NLS-1$ //$NON-NLS-2$
private static final CommandLineOption OPTION_IU_PROFILE_PROPS = new CommandLineOption(new String[] {"-iuProfileproperties"}, Messages.Help_lt_path_gt, Messages.Help_path_to_IU_profile_properties_file); //$NON-NLS-1$
private static final CommandLineOption OPTION_PROFILE_PROPS = new CommandLineOption(new String[] {"-profileproperties"}, Messages.Help_lt_comma_separated_list_gt, Messages.Help_A_list_of_properties_in_the_form_key_value_pairs); //$NON-NLS-1$
private static final CommandLineOption OPTION_ROAMING = new CommandLineOption(new String[] {"-roaming"}, null, Messages.Help_Indicates_that_the_product_can_be_moved); //$NON-NLS-1$
private static final CommandLineOption OPTION_P2_OS = new CommandLineOption(new String[] {"-p2.os"}, null, Messages.Help_The_OS_when_profile_is_created); //$NON-NLS-1$
private static final CommandLineOption OPTION_P2_WS = new CommandLineOption(new String[] {"-p2.ws"}, null, Messages.Help_The_WS_when_profile_is_created); //$NON-NLS-1$
private static final CommandLineOption OPTION_P2_ARCH = new CommandLineOption(new String[] {"-p2.arch"}, null, Messages.Help_The_ARCH_when_profile_is_created); //$NON-NLS-1$
private static final CommandLineOption OPTION_P2_NL = new CommandLineOption(new String[] {"-p2.nl"}, null, Messages.Help_The_NL_when_profile_is_created); //$NON-NLS-1$
private static final CommandLineOption OPTION_PURGEHISTORY = new CommandLineOption(new String[] {"-purgeHistory"}, null, Messages.Help_Purge_the_install_registry); //$NON-NLS-1$
private static final CommandLineOption OPTION_FOLLOW_REFERENCES = new CommandLineOption(new String[] {"-followReferences"}, null, Messages.Help_Follow_references); //$NON-NLS-1$
private static final CommandLineOption OPTION_TAG = new CommandLineOption(new String[] {"-tag"}, Messages.Help_lt_name_gt, Messages.Help_Defines_a_tag_for_provisioning_session); //$NON-NLS-1$
private static final CommandLineOption OPTION_LIST_TAGS = new CommandLineOption(new String[] {"-listTags"}, null, Messages.Help_List_Tags); //$NON-NLS-1$
private static final CommandLineOption OPTION_DOWNLOAD_ONLY = new CommandLineOption(new String[] {"-downloadOnly"}, null, Messages.Help_Download_Only); //$NON-NLS-1$
private static final CommandLineOption OPTION_IGNORED = new CommandLineOption(new String[] {"-showLocation", "-eclipse.password", "-eclipse.keyring"}, null, ""); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
private static final Integer EXIT_ERROR = 13;
static private final String FLAVOR_DEFAULT = "tooling"; //$NON-NLS-1$
static private final String PROP_P2_PROFILE = "eclipse.p2.profile"; //$NON-NLS-1$
static private final String NO_ARTIFACT_REPOSITORIES_AVAILABLE = "noArtifactRepositoriesAvailable"; //$NON-NLS-1$
private static final String FOLLOW_ARTIFACT_REPOSITORY_REFERENCES = "org.eclipse.equinox.p2.director.followArtifactRepositoryReferences"; //$NON-NLS-1$
private static final String LIST_GROUPS_SHORTCUT = "Q:GROUP"; //$NON-NLS-1$
private static final String QUERY_SEPARATOR = "Q:"; //$NON-NLS-1$
private static final String QUERY_SEPARATOR_SMALL = "q:"; //$NON-NLS-1$
public static final String LINE_SEPARATOR = System.lineSeparator();
private static void getURIs(List<URI> uris, String spec) throws CoreException {
if (spec == null)
return;
String[] urlSpecs = StringHelper.getArrayFromString(spec, ',');
for (String urlSpec : urlSpecs) {
try {
uris.add(new URI(urlSpec));
} catch (URISyntaxException e1) {
try {
uris.add(URIUtil.fromString(urlSpec));
} catch (URISyntaxException e) {
throw new ProvisionException(NLS.bind(Messages.unable_to_parse_0_to_uri_1, urlSpec, e.getMessage()), e);
}
}
}
}
private static String getRequiredArgument(String[] args, int argIdx) throws CoreException {
if (argIdx < args.length) {
String arg = args[argIdx];
if (!arg.startsWith("-")) //$NON-NLS-1$
return arg;
}
throw new ProvisionException(NLS.bind(Messages.option_0_requires_an_argument, args[argIdx - 1]));
}
private static String getOptionalArgument(String[] args, int argIdx) {
//Look ahead to the next argument
++argIdx;
if (argIdx < args.length) {
String arg = args[argIdx];
if (!arg.startsWith("-")) //$NON-NLS-1$
return arg;
}
return null;
}
private static void parseIUsArgument(List<IQuery<IInstallableUnit>> vnames, String arg) {
String[] roots = StringHelper.getArrayFromString(arg, ',');
for (String root : roots) {
if (root.equalsIgnoreCase(LIST_GROUPS_SHORTCUT)) {
vnames.add(new PrettyQuery<>(QueryUtil.createIUGroupQuery(), "All groups")); //$NON-NLS-1$
continue;
}
if (root.startsWith(QUERY_SEPARATOR) || root.startsWith(QUERY_SEPARATOR_SMALL)) {
String queryString = root.substring(2);
vnames.add(new PrettyQuery<>(QueryUtil.createQuery(queryString, new Object[0]), queryString));
continue;
}
IVersionedId vId = VersionedId.parse(root);
Version v = vId.getVersion();
IQuery<IInstallableUnit> query = new PrettyQuery<>(QueryUtil.createIUQuery(vId.getId(), Version.emptyVersion.equals(v) ? VersionRange.emptyRange : new VersionRange(v, true, v, true)), root);
vnames.add(query);
}
}
private static File processFileArgument(String arg) {
if (arg.startsWith("file:")) //$NON-NLS-1$
arg = arg.substring(5);
// we create a path object here to handle ../ entries in the middle of paths
return Path.fromOSString(arg).toFile();
}
private IArtifactRepositoryManager artifactManager;
IMetadataRepositoryManager metadataManager;
private URI[] artifactReposForRemoval;
private URI[] metadataReposForRemoval;
private final List<URI> artifactRepositoryLocations = new ArrayList<>();
private final List<URI> metadataRepositoryLocations = new ArrayList<>();
private final List<IQuery<IInstallableUnit>> rootsToInstall = new ArrayList<>();
private final List<IQuery<IInstallableUnit>> rootsToUninstall = new ArrayList<>();
private final List<IQuery<IInstallableUnit>> rootsToList = new ArrayList<>();
private File bundlePool = null;
private File destination;
private File sharedLocation;
private String flavor;
private boolean printHelpInfo = false;
private boolean printIUList = false;
private boolean printRootIUList = false;
private boolean printTags = false;
private IUListFormatter listFormat;
private String revertToPreviousState = NOTHING_TO_REVERT_TO;
private static String NOTHING_TO_REVERT_TO = "-1"; //$NON-NLS-1$
private static String REVERT_TO_PREVIOUS = "0"; //$NON-NLS-1$
private boolean verifyOnly = false;
private boolean roamingProfile = false;
private boolean purgeRegistry = false;
private boolean followReferences = false;
private boolean downloadOnly = false;
private String profileId;
private String profileProperties; // a comma-separated list of property pairs "tag=value"
private String iuProfileProperties; // path to Properties file with IU profile properties
private String ws;
private String os;
private String arch;
private String nl;
private String tag;
private IEngine engine;
private boolean noProfileId = false;
private IPlanner planner;
private ILog log = new DefaultLog();
private IProvisioningAgent targetAgent;
private boolean targetAgentIsSelfAndUp = false;
private boolean noArtifactRepositorySpecified = false;
protected ProfileChangeRequest buildProvisioningRequest(IProfile profile, Collection<IInstallableUnit> installs, Collection<IInstallableUnit> uninstalls) {
ProfileChangeRequest request = new ProfileChangeRequest(profile);
markRoots(request, installs);
markRoots(request, uninstalls);
request.addAll(installs);
request.removeAll(uninstalls);
buildIUProfileProperties(request);
return request;
}
// read the given file into a Properties object
private Properties loadProperties(File file) {
if (!file.exists()) {
// log a warning and return
log.log(new Status(WARNING, ID, NLS.bind(Messages.File_does_not_exist, file.getAbsolutePath())));
return null;
}
Properties properties = new Properties();
try (InputStream input = new BufferedInputStream(new FileInputStream(file))) {
properties.load(input);
} catch (IOException e) {
log.log(new Status(ERROR, ID, NLS.bind(Messages.Problem_loading_file, file.getAbsolutePath()), e));
return null;
}
return properties;
}
private void buildIUProfileProperties(IProfileChangeRequest request) {
final String KEYWORD_KEY = "key"; //$NON-NLS-1$
final String KEYWORD_VALUE = "value"; //$NON-NLS-1$
final String KEYWORD_VERSION = "version"; //$NON-NLS-1$
if (iuProfileProperties == null)
return;
// read the file into a Properties object for easier processing
Properties properties = loadProperties(new File(iuProfileProperties));
if (properties == null)
return;
// format for a line in the properties input file is <id>.<keyword>.<uniqueNumber>=value
// id is the IU id
// keyword is either "key" or "value"
// uniqueNumber is used to group keys and values together
Set<String> alreadyProcessed = new HashSet<>();
for (Object object : properties.keySet()) {
String line = (String) object;
int index = line.lastIndexOf('.');
if (index == -1)
continue;
int num = -1;
String id = null;
try {
num = Integer.parseInt(line.substring(index + 1));
line = line.substring(0, index);
index = line.lastIndexOf('.');
if (index == -1)
continue;
// skip over the keyword
id = line.substring(0, index);
} catch (NumberFormatException e) {
log.log(new Status(WARNING, ID, NLS.bind(Messages.Bad_format, line, iuProfileProperties), e));
continue;
} catch (IndexOutOfBoundsException e) {
log.log(new Status(WARNING, ID, NLS.bind(Messages.Bad_format, line, iuProfileProperties), e));
continue;
}
String versionLine = id + '.' + KEYWORD_VERSION + '.' + num;
String keyLine = id + '.' + KEYWORD_KEY + '.' + num;
String valueLine = id + '.' + KEYWORD_VALUE + '.' + num;
if (alreadyProcessed.contains(versionLine) || alreadyProcessed.contains(keyLine) || alreadyProcessed.contains(valueLine))
continue;
// skip over this key/value pair next time we see it
alreadyProcessed.add(versionLine);
alreadyProcessed.add(keyLine);
alreadyProcessed.add(valueLine);
Version version = Version.create((String) properties.get(versionLine)); // it is ok to have a null version
String key = (String) properties.get(keyLine);
String value = (String) properties.get(valueLine);
if (key == null || value == null) {
String message = NLS.bind(Messages.Unmatched_iu_profile_property_key_value, key + '/' + value);
log.log(new Status(WARNING, ID, message));
continue;
}
// lookup the IU - a null version matches all versions
IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(id, version);
// if we don't have a version the choose the latest.
if (version == null)
query = QueryUtil.createLatestQuery(query);
IQueryResult<IInstallableUnit> qr = getInstallableUnits(null, query, null);
if (qr.isEmpty()) {
String msg = NLS.bind(Messages.Cannot_set_iu_profile_property_iu_does_not_exist, id + '/' + version);
log.log(new Status(WARNING, ID, msg));
continue;
}
IInstallableUnit iu = qr.iterator().next();
request.setInstallableUnitProfileProperty(iu, key, value);
}
}
private void cleanupRepositories() {
if (artifactReposForRemoval != null && artifactManager != null) {
for (int i = 0; i < artifactReposForRemoval.length && artifactReposForRemoval[i] != null; i++) {
artifactManager.removeRepository(artifactReposForRemoval[i]);
}
}
if (metadataReposForRemoval != null && metadataManager != null) {
for (int i = 0; i < metadataReposForRemoval.length && metadataReposForRemoval[i] != null; i++) {
metadataManager.removeRepository(metadataReposForRemoval[i]);
}
}
}
private IQueryResult<IInstallableUnit> collectRootIUs(IQuery<IInstallableUnit> query) {
IProgressMonitor nullMonitor = new NullProgressMonitor();
int top = metadataRepositoryLocations.size();
if (top == 0)
return getInstallableUnits(null, query, nullMonitor);
List<IQueryable<IInstallableUnit>> locationQueryables = new ArrayList<>(top);
for (int i = 0; i < top; i++)
locationQueryables.add(new LocationQueryable(metadataRepositoryLocations.get(i)));
return QueryUtil.compoundQueryable(locationQueryables).query(query, nullMonitor);
}
private Collection<IInstallableUnit> collectRoots(IProfile profile, List<IQuery<IInstallableUnit>> rootNames, boolean forInstall) throws CoreException {
ArrayList<IInstallableUnit> allRoots = new ArrayList<>();
for (IQuery<IInstallableUnit> rootQuery : rootNames) {
IQueryResult<IInstallableUnit> roots = null;
if (forInstall)
roots = collectRootIUs(QueryUtil.createLatestQuery(rootQuery));
if (roots == null || roots.isEmpty())
roots = profile.query(rootQuery, new NullProgressMonitor());
Iterator<IInstallableUnit> itor = roots.iterator();
if (!itor.hasNext())
throw new CoreException(new Status(ERROR, ID, NLS.bind(Messages.Missing_IU, rootQuery)));
do {
allRoots.add(itor.next());
} while (itor.hasNext());
}
return allRoots;
}
private String getEnvironmentProperty() {
HashMap<String, String> values = new HashMap<>();
if (os != null)
values.put("osgi.os", os); //$NON-NLS-1$
if (nl != null)
values.put("osgi.nl", nl); //$NON-NLS-1$
if (ws != null)
values.put("osgi.ws", ws); //$NON-NLS-1$
if (arch != null)
values.put("osgi.arch", arch); //$NON-NLS-1$
return values.isEmpty() ? null : toString(values);
}
private IProfile getProfile() {
IProfileRegistry profileRegistry = targetAgent.getService(IProfileRegistry.class);
if (profileId == null) {
profileId = IProfileRegistry.SELF;
noProfileId = true;
}
return profileRegistry.getProfile(profileId);
}
private IProfile initializeProfile() throws CoreException {
IProfile profile = getProfile();
if (profile == null) {
if (destination == null)
missingArgument("destination"); //$NON-NLS-1$
if (flavor == null)
flavor = System.getProperty("eclipse.p2.configurationFlavor", FLAVOR_DEFAULT); //$NON-NLS-1$
Map<String, String> props = new HashMap<>();
props.put(IProfile.PROP_INSTALL_FOLDER, destination.toString());
if (bundlePool == null)
props.put(IProfile.PROP_CACHE, sharedLocation == null ? destination.getAbsolutePath() : sharedLocation.getAbsolutePath());
else
props.put(IProfile.PROP_CACHE, bundlePool.getAbsolutePath());
if (roamingProfile)
props.put(IProfile.PROP_ROAMING, Boolean.TRUE.toString());
String env = getEnvironmentProperty();
if (env != null)
props.put(IProfile.PROP_ENVIRONMENTS, env);
if (profileProperties != null)
putProperties(profileProperties, props);
profile = targetAgent.getService(IProfileRegistry.class).addProfile(profileId, props);
}
return profile;
}
private void initializeRepositories() throws CoreException {
if (rootsToInstall.isEmpty() && revertToPreviousState == NOTHING_TO_REVERT_TO && !printIUList)
// Not much point initializing repositories if we have nothing to install
return;
if (artifactRepositoryLocations == null)
missingArgument("-artifactRepository"); //$NON-NLS-1$
artifactManager = targetAgent.getService(IArtifactRepositoryManager.class);
if (artifactManager == null)
throw new ProvisionException(Messages.Application_NoManager);
int removalIdx = 0;
boolean anyValid = false; // do we have any valid repos or did they all fail to load?
artifactReposForRemoval = new URI[artifactRepositoryLocations.size()];
for (URI location : artifactRepositoryLocations) {
try {
if (!artifactManager.contains(location)) {
artifactManager.loadRepository(location, null);
artifactReposForRemoval[removalIdx++] = location;
}
anyValid = true;
} catch (ProvisionException e) {
//one of the repositories did not load
log.log(e.getStatus());
}
}
if (!anyValid)
noArtifactRepositorySpecified = true;
if (metadataRepositoryLocations == null)
missingArgument("metadataRepository"); //$NON-NLS-1$
metadataManager = targetAgent.getService(IMetadataRepositoryManager.class);
if (metadataManager == null)
throw new ProvisionException(Messages.Application_NoManager);
removalIdx = 0;
anyValid = false; // do we have any valid repos or did they all fail to load?
int top = metadataRepositoryLocations.size();
metadataReposForRemoval = new URI[top];
for (int i = 0; i < top; i++) {
URI location = metadataRepositoryLocations.get(i);
try {
if (!metadataManager.contains(location)) {
metadataManager.loadRepository(location, null);
metadataReposForRemoval[removalIdx++] = location;
}
anyValid = true;
} catch (ProvisionException e) {
//one of the repositories did not load
log.log(e.getStatus());
}
}
if (!anyValid)
//all repositories failed to load
throw new ProvisionException(Messages.Application_NoRepositories);
if (!EngineActivator.EXTENDED)
return;
File[] extensions = EngineActivator.getExtensionsDirectories();
for (File f : extensions) {
metadataManager.addRepository(f.toURI());
metadataManager.setRepositoryProperty(f.toURI(), EngineActivator.P2_FRAGMENT_PROPERTY, Boolean.TRUE.toString());
metadataRepositoryLocations.add(f.toURI());
artifactManager.addRepository(f.toURI());
artifactManager.setRepositoryProperty(f.toURI(), EngineActivator.P2_FRAGMENT_PROPERTY, Boolean.TRUE.toString());
artifactRepositoryLocations.add(f.toURI());
}
}
private void adjustDestination() {
//Detect the desire to have a bundled mac application and tweak the environment
if (destination == null)
return;
if (org.eclipse.osgi.service.environment.Constants.OS_MACOSX.equals(os) && destination.getName().endsWith(".app")) //$NON-NLS-1$
destination = new File(destination, "Contents/Eclipse"); //$NON-NLS-1$
}
private URI getP2DataAreaLocation(BundleContext context) {
URI p2DataArea;
if (destination != null || sharedLocation != null) {
File dataAreaFile = sharedLocation == null ? new File(destination, "p2") : sharedLocation;//$NON-NLS-1$
p2DataArea = dataAreaFile.toURI();
} else {
p2DataArea = null;
}
if (p2DataArea == null) {
final String currentAgentFiler = '(' + IProvisioningAgent.SERVICE_CURRENT + '=' + "true)"; //$NON-NLS-1$
try {
Collection<ServiceReference<IProvisioningAgent>> refs;
refs = context.getServiceReferences(IProvisioningAgent.class, currentAgentFiler);
if (!refs.isEmpty()) {
targetAgent = context.getService(refs.iterator().next());
targetAgentIsSelfAndUp = true;
}
} catch (InvalidSyntaxException e) {
//Can't happen the filter never changes
}
}
return p2DataArea;
}
// Implement something here to position "p2 folder" correctly
private void initializeServices() throws CoreException {
BundleContext context = Activator.getContext();
ServiceReference<IProvisioningAgentProvider> agentProviderRef = context.getServiceReference(IProvisioningAgentProvider.class);
IProvisioningAgentProvider provider = context.getService(agentProviderRef);
URI p2DataArea = getP2DataAreaLocation(context);
if (targetAgent == null) {
targetAgent = provider.createAgent(p2DataArea);
targetAgent.registerService(IProvisioningAgent.INSTALLER_AGENT, provider.createAgent(null));
}
context.ungetService(agentProviderRef);
if (profileId == null) {
if (destination != null) {
File configIni = new File(destination, "configuration/config.ini"); //$NON-NLS-1$
Properties ciProps = new Properties();
try (InputStream in = new BufferedInputStream(new FileInputStream(configIni));) {
ciProps.load(in);
profileId = ciProps.getProperty(PROP_P2_PROFILE);
} catch (IOException e) {
// Ignore
}
if (profileId == null)
profileId = destination.toString();
}
}
if (profileId != null)
targetAgent.registerService(PROP_P2_PROFILE, profileId);
else
targetAgent.unregisterService(PROP_P2_PROFILE, null);
IDirector director = targetAgent.getService(IDirector.class);
if (director == null)
throw new ProvisionException(Messages.Missing_director);
planner = targetAgent.getService(IPlanner.class);
if (planner == null)
throw new ProvisionException(Messages.Missing_planner);
engine = targetAgent.getService(IEngine.class);
if (engine == null)
throw new ProvisionException(Messages.Missing_Engine);
targetAgent.registerService(UIServices.SERVICE_NAME, new AvoidTrustPromptService());
IProvisioningEventBus eventBus = targetAgent.getService(IProvisioningEventBus.class);
if (eventBus == null)
return;
eventBus.addListener(this);
}
/*
* See bug: https://bugs.eclipse.org/340971 Using the event bus to detect
* whether or not a repository was added in a touchpoint action. If it was, then
* (if it exists) remove it from our list of repos to remove after we complete
* our install.
*/
@Override
public void notify(EventObject o) {
if (!(o instanceof RepositoryEvent))
return;
RepositoryEvent event = (RepositoryEvent) o;
if (RepositoryEvent.ADDED != event.getKind())
return;
//TODO BE CAREFUL SINCE WE ARE MODIFYING THE SELF PROFILE
int type = event.getRepositoryType();
URI location = event.getRepositoryLocation();
if (IRepository.TYPE_ARTIFACT == type && artifactReposForRemoval != null) {
for (int i = 0; i < artifactReposForRemoval.length; i++) {
if (artifactReposForRemoval[i] != null && URIUtil.sameURI(artifactReposForRemoval[i], (location))) {
artifactReposForRemoval[i] = null;
break;
}
}
// either found or not found. either way, we're done here
return;
}
if (IRepository.TYPE_METADATA == type && metadataReposForRemoval != null) {
for (int i = 0; i < metadataReposForRemoval.length; i++) {
if (metadataReposForRemoval[i] != null && URIUtil.sameURI(metadataReposForRemoval[i], (location))) {
metadataReposForRemoval[i] = null;
break;
}
}
// either found or not found. either way, we're done here
return;
}
}
private void markRoots(IProfileChangeRequest request, Collection<IInstallableUnit> roots) {
for (IInstallableUnit root : roots) {
request.setInstallableUnitProfileProperty(root, IProfile.PROP_PROFILE_ROOT_IU, Boolean.TRUE.toString());
}
}
private void missingArgument(String argumentName) throws CoreException {
throw new ProvisionException(NLS.bind(Messages.Missing_Required_Argument, argumentName));
}
private void performList() throws CoreException {
if (metadataRepositoryLocations.isEmpty())
missingArgument("metadataRepository"); //$NON-NLS-1$
ArrayList<IInstallableUnit> allRoots = new ArrayList<>();
if (rootsToList.size() == 0) {
Iterator<IInstallableUnit> roots = collectRootIUs(QueryUtil.createIUAnyQuery()).iterator();
while (roots.hasNext())
allRoots.add(roots.next());
} else {
for (IQuery<IInstallableUnit> root : rootsToList) {
Iterator<IInstallableUnit> roots = collectRootIUs(root).iterator();
while (roots.hasNext())
allRoots.add(roots.next());
}
}
allRoots.sort(null);
String formattedString = listFormat.format(allRoots);
System.out.println(formattedString);
}
private void performProvisioningActions() throws CoreException {
IProfile profile = initializeProfile();
Collection<IInstallableUnit> installs = collectRoots(profile, rootsToInstall, true);
Collection<IInstallableUnit> uninstalls = collectRoots(profile, rootsToUninstall, false);
// keep this result status in case there is a problem so we can report it to the user
boolean wasRoaming = Boolean.parseBoolean(profile.getProperty(IProfile.PROP_ROAMING));
try {
updateRoamingProperties(profile);
ProvisioningContext context = new ProvisioningContext(targetAgent);
context.setMetadataRepositories(metadataRepositoryLocations.stream().toArray(URI[]::new));
context.setArtifactRepositories(artifactRepositoryLocations.stream().toArray(URI[]::new));
context.setProperty(ProvisioningContext.FOLLOW_REPOSITORY_REFERENCES, String.valueOf(followReferences));
context.setProperty(FOLLOW_ARTIFACT_REPOSITORY_REFERENCES, String.valueOf(followReferences));
ProfileChangeRequest request = buildProvisioningRequest(profile, installs, uninstalls);
printRequest(request);
planAndExecute(profile, context, request);
} finally {
// if we were originally were set to be roaming and we changed it, change it back before we return
if (wasRoaming && !Boolean.parseBoolean(profile.getProperty(IProfile.PROP_ROAMING))) {
setRoaming(profile);
}
}
}
private void planAndExecute(IProfile profile, ProvisioningContext context, ProfileChangeRequest request) throws CoreException {
IProvisioningPlan result = planner.getProvisioningPlan(request, context, new NullProgressMonitor());
IStatus operationStatus = result.getStatus();
if (!operationStatus.isOK()) {
throw new CoreException(operationStatus);
}
log.log(operationStatus);
executePlan(context, result);
}
private void executePlan(ProvisioningContext context, IProvisioningPlan result) throws CoreException {
if (verifyOnly) {
return;
}
IStatus operationStatus;
if (!downloadOnly)
operationStatus = PlanExecutionHelper.executePlan(result, engine, context, new NullProgressMonitor());
else
operationStatus = PlanExecutionHelper.executePlan(result, engine, PhaseSetFactory.createPhaseSetIncluding(new String[] {PhaseSetFactory.PHASE_COLLECT, PhaseSetFactory.PHASE_CHECK_TRUST}), context, new NullProgressMonitor());
switch (operationStatus.getSeverity()) {
case OK :
break;
case INFO :
case WARNING :
log.log(operationStatus);
break;
// All other status codes correspond to IStatus.isOk() == false
default :
if (noArtifactRepositorySpecified && hasNoRepositoryFound(operationStatus)) {
throw new ProvisionException(Messages.Application_NoRepositories);
}
throw new CoreException(operationStatus);
}
if (tag == null) {
return;
}
long newState = result.getProfile().getTimestamp();
IProfileRegistry registry = targetAgent.getService(IProfileRegistry.class);
registry.setProfileStateProperty(result.getProfile().getProfileId(), newState, IProfile.STATE_PROP_TAG, tag);
}
private boolean hasNoRepositoryFound(IStatus status) {
if (status.getException() != null && NO_ARTIFACT_REPOSITORIES_AVAILABLE.equals(status.getException().getMessage()))
return true;
if (status.isMultiStatus()) {
for (IStatus child : status.getChildren()) {
if (hasNoRepositoryFound(child))
return true;
}
}
return false;
}
public void processArguments(String[] args) throws CoreException {
if (args == null) {
printHelpInfo = true;
return;
}
// Set platform environment defaults
EnvironmentInfo info = ServiceHelper.getService(Activator.getContext(), EnvironmentInfo.class);
os = info.getOS();
ws = info.getWS();
nl = info.getNL();
arch = info.getOSArch();
for (int i = 0; i < args.length; i++) {
// check for args without parameters (i.e., a flag arg)
String opt = args[i];
if (OPTION_LIST.isOption(opt)) {
printIUList = true;
String optionalArgument = getOptionalArgument(args, i);
if (optionalArgument != null) {
parseIUsArgument(rootsToList, optionalArgument);
i++;
}
continue;
}
if (OPTION_LIST_FORMAT.isOption(opt)) {
String formatString = getRequiredArgument(args, ++i);
listFormat = new IUListFormatter(formatString);
continue;
}
if (OPTION_LIST_INSTALLED.isOption(opt)) {
printRootIUList = true;
continue;
}
if (OPTION_LIST_TAGS.isOption(opt)) {
printTags = true;
continue;
}
if (OPTION_DOWNLOAD_ONLY.isOption(opt)) {
downloadOnly = true;
continue;
}
if (OPTION_HELP.isOption(opt)) {
printHelpInfo = true;
continue;
}
if (OPTION_INSTALL_IU.isOption(opt)) {
parseIUsArgument(rootsToInstall, getRequiredArgument(args, ++i));
continue;
}
if (OPTION_UNINSTALL_IU.isOption(opt)) {
parseIUsArgument(rootsToUninstall, getRequiredArgument(args, ++i));
continue;
}
if (OPTION_REVERT.isOption(opt)) {
String targettedState = getOptionalArgument(args, i);
if (targettedState == null) {
revertToPreviousState = REVERT_TO_PREVIOUS;
} else {
i++;
revertToPreviousState = targettedState;
}
continue;
}
if (OPTION_PROFILE.isOption(opt)) {
profileId = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_FLAVOR.isOption(opt)) {
flavor = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_SHARED.isOption(opt)) {
if (++i < args.length) {
String nxt = args[i];
if (nxt.startsWith("-")) //$NON-NLS-1$
--i; // Oops, that's the next option, not an argument
else
sharedLocation = processFileArgument(nxt);
}
if (sharedLocation == null)
// -shared without an argument means "Use default shared area"
sharedLocation = Path.fromOSString(System.getProperty("user.home")).append(".p2/").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
if (OPTION_DESTINATION.isOption(opt)) {
destination = processFileArgument(getRequiredArgument(args, ++i));
continue;
}
if (OPTION_BUNDLEPOOL.isOption(opt)) {
bundlePool = processFileArgument(getRequiredArgument(args, ++i));
continue;
}
if (OPTION_METADATAREPOS.isOption(opt)) {
getURIs(metadataRepositoryLocations, getRequiredArgument(args, ++i));
continue;
}
if (OPTION_ARTIFACTREPOS.isOption(opt)) {
getURIs(artifactRepositoryLocations, getRequiredArgument(args, ++i));
continue;
}
if (OPTION_REPOSITORIES.isOption(opt)) {
String arg = getRequiredArgument(args, ++i);
getURIs(metadataRepositoryLocations, arg);
getURIs(artifactRepositoryLocations, arg);
continue;
}
if (OPTION_PROFILE_PROPS.isOption(opt)) {
profileProperties = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_IU_PROFILE_PROPS.isOption(opt)) {
iuProfileProperties = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_ROAMING.isOption(opt)) {
roamingProfile = true;
continue;
}
if (OPTION_VERIFY_ONLY.isOption(opt)) {
verifyOnly = true;
continue;
}
if (OPTION_PURGEHISTORY.isOption(opt)) {
purgeRegistry = true;
continue;
}
if (OPTION_FOLLOW_REFERENCES.isOption(opt)) {
followReferences = true;
continue;
}
if (OPTION_P2_OS.isOption(opt)) {
os = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_P2_WS.isOption(opt)) {
ws = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_P2_NL.isOption(opt)) {
nl = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_P2_ARCH.isOption(opt)) {
arch = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_TAG.isOption(opt)) {
tag = getRequiredArgument(args, ++i);
continue;
}
if (OPTION_IGNORED.isOption(opt)) {
String optionalArgument = getOptionalArgument(args, i);
if (optionalArgument != null) {
i++;
}
continue;
}
if (opt != null && opt.length() > 0)
throw new ProvisionException(NLS.bind(Messages.unknown_option_0, opt));
}
if (listFormat != null && !printIUList && !printRootIUList) {
throw new ProvisionException(NLS.bind(Messages.ArgRequiresOtherArgs, //
new String[] {OPTION_LIST_FORMAT.identifiers[0], OPTION_LIST.identifiers[0], OPTION_LIST_INSTALLED.identifiers[0]}));
}
else if (!printHelpInfo && !printIUList && !printRootIUList && !printTags && !purgeRegistry && rootsToInstall.isEmpty() && rootsToUninstall.isEmpty() && revertToPreviousState == NOTHING_TO_REVERT_TO) {
log.printOut(Messages.Help_Missing_argument);
printHelpInfo = true;
}
if (listFormat == null) {
listFormat = new IUListFormatter("${id}=${version}"); //$NON-NLS-1$
}
}
/**
* @param pairs a comma separated list of tag=value pairs
* @param properties the collection into which the pairs are put
*/
private void putProperties(String pairs, Map<String, String> properties) {
String[] propPairs = StringHelper.getArrayFromString(pairs, ',');
for (String propPair : propPairs) {
int eqIdx = propPair.indexOf('=');
if (eqIdx < 0)
continue;
String tag = propPair.substring(0, eqIdx).trim();
if (tag.length() == 0)
continue;
String value = propPair.substring(eqIdx + 1).trim();
if (value.length() > 0)
properties.put(tag, value);
}
}
private void cleanupServices() {
//dispose agent, only if it is not already up and running
if (targetAgent != null && !targetAgentIsSelfAndUp) {
targetAgent.stop();
targetAgent = null;
}
}
public Object run(String[] args) {
long time = System.currentTimeMillis();
try {
processArguments(args);
if (printHelpInfo)
performHelpInfo();
else {
adjustDestination();
initializeServices();
if (!(printIUList || printRootIUList || printTags)) {
if (!canInstallInDestination()) {
log.printOut(NLS.bind(Messages.Cant_write_in_destination, destination.getAbsolutePath()));
return EXIT_ERROR;
}
}
initializeRepositories();
if (revertToPreviousState != NOTHING_TO_REVERT_TO) {
revertToPreviousState();
} else if (!(rootsToInstall.isEmpty() && rootsToUninstall.isEmpty()))
performProvisioningActions();
if (printIUList)
performList();
if (printRootIUList)
performListInstalledRoots();
if (printTags)
performPrintTags();
if (purgeRegistry)
purgeRegistry();
log.printOut(NLS.bind(Messages.Operation_complete, Long.valueOf(System.currentTimeMillis() - time)));
}
return IApplication.EXIT_OK;
} catch (CoreException e) {
IStatus error = e.getStatus();
log.printOut(Messages.Operation_failed);
printError(error, 0);
log.log(error);
//set empty exit data to suppress error dialog from launcher
setSystemProperty("eclipse.exitdata", ""); //$NON-NLS-1$ //$NON-NLS-2$
return EXIT_ERROR;
} finally {
log.close();
cleanupRepositories();
cleanupServices();
}
}
private void purgeRegistry() throws ProvisionException {
if (getProfile() == null)
return;
IProfileRegistry registry = targetAgent.getService(IProfileRegistry.class);
long[] allProfiles = registry.listProfileTimestamps(profileId);
for (int i = 0; i < allProfiles.length - 1; i++) {
registry.removeProfile(profileId, allProfiles[i]);
}
}
private void revertToPreviousState() throws CoreException {
IProfile profile = initializeProfile();
IProfileRegistry profileRegistry = targetAgent.getService(IProfileRegistry.class);
IProfile targetProfile = null;
if (revertToPreviousState == REVERT_TO_PREVIOUS) {
long[] profiles = profileRegistry.listProfileTimestamps(profile.getProfileId());
if (profiles.length == 0)
return;
targetProfile = profileRegistry.getProfile(profile.getProfileId(), profiles[profiles.length - 1]);
} else {
targetProfile = profileRegistry.getProfile(profile.getProfileId(), getTimestampToRevertTo(profileRegistry, profile.getProfileId()));
}
if (targetProfile == null)
throw new CoreException(new Status(ERROR, ID, Messages.Missing_profile));
IProvisioningPlan plan = planner.getDiffPlan(profile, targetProfile, new NullProgressMonitor());
ProvisioningContext context = new ProvisioningContext(targetAgent);
context.setMetadataRepositories(metadataRepositoryLocations.toArray(new URI[metadataRepositoryLocations.size()]));
context.setArtifactRepositories(artifactRepositoryLocations.toArray(new URI[artifactRepositoryLocations.size()]));
context.setProperty(ProvisioningContext.FOLLOW_REPOSITORY_REFERENCES, String.valueOf(followReferences));
context.setProperty(FOLLOW_ARTIFACT_REPOSITORY_REFERENCES, String.valueOf(followReferences));
executePlan(context, plan);
}
private long getTimestampToRevertTo(IProfileRegistry profileRegistry, String profId) {
long timestampToRevertTo = -1;
try {
//Deal with the case where the revert points to a timestamp
timestampToRevertTo = Long.valueOf(revertToPreviousState).longValue();
} catch (NumberFormatException e) {
//Deal with the case where the revert points to tag
Map<String, String> tags = profileRegistry.getProfileStateProperties(profId, IProfile.STATE_PROP_TAG);
Set<Entry<String, String>> entries = tags.entrySet();
for (Entry<String, String> entry : entries) {
if (entry.getValue().equals(revertToPreviousState))
try {
long tmp = Long.valueOf(entry.getKey()).longValue();
if (tmp > timestampToRevertTo)
timestampToRevertTo = tmp;
} catch (NumberFormatException e2) {
//Not expected since the value is supposed to be a timestamp as per API
}
}
}
return timestampToRevertTo;
}
/**
* Sets a system property, using the EnvironmentInfo service if possible.
*/
private void setSystemProperty(String key, String value) {
EnvironmentInfo env = ServiceHelper.getService(Activator.getContext(), EnvironmentInfo.class);
if (env != null) {
env.setProperty(key, value);
} else {
System.getProperties().put(key, value);
}
}
IQueryResult<IInstallableUnit> getInstallableUnits(URI location, IQuery<IInstallableUnit> query, IProgressMonitor monitor) {
IQueryable<IInstallableUnit> queryable = null;
if (location == null) {
queryable = metadataManager;
} else {
try {
queryable = metadataManager.loadRepository(location, monitor);
} catch (ProvisionException e) {
//repository is not available - just return empty result
}
}
if (queryable != null)
return queryable.query(query, monitor);
return Collector.emptyCollector();
}
private void performHelpInfo() {
CommandLineOption[] allOptions = new CommandLineOption[] {OPTION_HELP, OPTION_LIST, OPTION_LIST_INSTALLED, OPTION_LIST_FORMAT, OPTION_INSTALL_IU, OPTION_UNINSTALL_IU, OPTION_REVERT, OPTION_DESTINATION, OPTION_DOWNLOAD_ONLY, OPTION_METADATAREPOS, OPTION_ARTIFACTREPOS, OPTION_REPOSITORIES, OPTION_VERIFY_ONLY, OPTION_TAG, OPTION_LIST_TAGS, OPTION_PROFILE, OPTION_FLAVOR, OPTION_SHARED, OPTION_BUNDLEPOOL, OPTION_PROFILE_PROPS, OPTION_IU_PROFILE_PROPS, OPTION_ROAMING, OPTION_P2_OS, OPTION_P2_WS, OPTION_P2_ARCH, OPTION_P2_NL, OPTION_PURGEHISTORY, OPTION_FOLLOW_REFERENCES};
for (CommandLineOption allOption : allOptions) {
allOption.appendHelp(System.out);
}
}
/*
* Set the roaming property on the given profile.
*/
private IStatus setRoaming(IProfile profile) {
ProfileChangeRequest request = new ProfileChangeRequest(profile);
request.setProfileProperty(IProfile.PROP_ROAMING, "true"); //$NON-NLS-1$
ProvisioningContext context = new ProvisioningContext(targetAgent);
context.setMetadataRepositories(new URI[0]);
context.setArtifactRepositories(new URI[0]);
IProvisioningPlan result = planner.getProvisioningPlan(request, context, new NullProgressMonitor());
return PlanExecutionHelper.executePlan(result, engine, context, new NullProgressMonitor());
}
@Override
public Object start(IApplicationContext context) throws Exception {
return run((String[]) context.getArguments().get("application.args")); //$NON-NLS-1$
}
private String toString(Map<String, String> context) {
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : context.entrySet()) {
if (result.length() > 0)
result.append(',');
result.append(entry.getKey());
result.append('=');
result.append(entry.getValue());
}
return result.toString();
}
private void updateRoamingProperties(IProfile profile) throws CoreException {
// if the user didn't specify a destination path on the command-line
// then we assume they are installing into the currently running
// instance and we don't have anything to update
if (destination == null)
return;
// if the user didn't set a profile id on the command-line this is ok if they
// also didn't set the destination path. (handled in the case above) otherwise throw an error.
if (noProfileId) // && destination != null
throw new ProvisionException(Messages.Missing_profileid);
// make sure that we are set to be roaming before we update the values
if (!Boolean.parseBoolean(profile.getProperty(IProfile.PROP_ROAMING)))
return;
ProfileChangeRequest request = new ProfileChangeRequest(profile);
if (!destination.equals(new File(profile.getProperty(IProfile.PROP_INSTALL_FOLDER))))
request.setProfileProperty(IProfile.PROP_INSTALL_FOLDER, destination.getAbsolutePath());
File cacheLocation = null;
if (bundlePool == null)
cacheLocation = sharedLocation == null ? destination.getAbsoluteFile() : sharedLocation.getAbsoluteFile();
else
cacheLocation = bundlePool.getAbsoluteFile();
if (!cacheLocation.equals(new File(profile.getProperty(IProfile.PROP_CACHE))))
request.setProfileProperty(IProfile.PROP_CACHE, cacheLocation.getAbsolutePath());
if (request.getProfileProperties().size() == 0)
return;
// otherwise we have to make a change so set the profile to be non-roaming so the
// values don't get recalculated to the wrong thing if we are flushed from memory - we
// will set it back later (see bug 269468)
request.setProfileProperty(IProfile.PROP_ROAMING, "false"); //$NON-NLS-1$
ProvisioningContext context = new ProvisioningContext(targetAgent);
context.setMetadataRepositories(new URI[0]);
context.setArtifactRepositories(new URI[0]);
IProvisioningPlan result = planner.getProvisioningPlan(request, context, new NullProgressMonitor());
IStatus status = PlanExecutionHelper.executePlan(result, engine, context, new NullProgressMonitor());
if (!status.isOK())
throw new CoreException(new MultiStatus(ID, ERROR, new IStatus[] {status}, NLS.bind(Messages.Cant_change_roaming, profile.getProfileId()), null));
}
@Override
public void stop() {
IProvisioningEventBus eventBus = targetAgent.getService(IProvisioningEventBus.class);
if (eventBus != null) {
eventBus.removeListener(this);
}
if (log != null) {
log.close();
}
}
public void setLog(ILog log) {
this.log = log;
}
private void performListInstalledRoots() throws CoreException {
IProfile profile = initializeProfile();
IQueryResult<IInstallableUnit> roots = profile.query(new UserVisibleRootQuery(), null);
Set<IInstallableUnit> sorted = new TreeSet<>(roots.toUnmodifiableSet());
for (IInstallableUnit iu : sorted)
System.out.println(iu.getId() + '/' + iu.getVersion());
}
private void performPrintTags() throws CoreException {
IProfile profile = initializeProfile();
IProfileRegistry registry = targetAgent.getService(IProfileRegistry.class);
Map<String, String> tags = registry.getProfileStateProperties(profile.getProfileId(), IProfile.STATE_PROP_TAG);
//Sort the tags from the most recent to the oldest
List<String> timeStamps = new ArrayList<>(tags.keySet());
timeStamps.sort(Collections.reverseOrder());
for (String timestamp : timeStamps) {
System.out.println(tags.get(timestamp));
}
}
private void printRequest(IProfileChangeRequest request) {
Collection<IInstallableUnit> toAdd = request.getAdditions();
for (IInstallableUnit added : toAdd) {
log.printOut(NLS.bind(Messages.Installing, added.getId(), added.getVersion()));
}
Collection<IInstallableUnit> toRemove = request.getRemovals();
for (IInstallableUnit removed : toRemove) {
log.printOut(NLS.bind(Messages.Uninstalling, removed.getId(), removed.getVersion()));
}
}
private void printError(IStatus status, int level) {
String prefix = emptyString(level);
String msg = status.getMessage();
log.printErr(prefix + msg);
Throwable cause = status.getException();
if (cause != null) {
// TODO This is very unreliable. It assumes that if the IStatus message is the same as the IStatus cause
// message the cause exception has no more data to offer. Better to just print it.
boolean isCauseMsg = msg.equals(cause.getMessage()) || msg.equals(cause.toString());
if (!isCauseMsg) {
log.printErr(prefix + "Caused by: "); //$NON-NLS-1$
printError(cause, level);
}
}
for (IStatus child : status.getChildren()) {
printError(child, level + 1);
}
}
private void printError(Throwable trace, int level) {
if (trace instanceof CoreException) {
printError(((CoreException) trace).getStatus(), level);
} else {
String prefix = emptyString(level);
log.printErr(prefix + trace.toString());
Throwable cause = trace.getCause();
if (cause != null) {
log.printErr(prefix + "Caused by: "); //$NON-NLS-1$
printError(cause, level);
}
}
}
private static String emptyString(int size) {
return IntStream.range(0, size).mapToObj(i -> "\t").collect(Collectors.joining()); //$NON-NLS-1$
}
private boolean canInstallInDestination() throws CoreException {
//When we are provisioning what we are running. We can always install.
if (targetAgentIsSelfAndUp)
return true;
if (destination == null)
missingArgument("destination"); //$NON-NLS-1$
return canWrite(destination);
}
private static boolean canWrite(File installDir) {
installDir.mkdirs(); //Force create the folders because otherwise the call to canWrite fails on Mac
return installDir.isDirectory() && Files.isWritable(installDir.toPath());
}
}