| /******************************************************************************* |
| * Copyright (c) 2007, 2008 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 |
| * Cloudsmith - https://bugs.eclipse.org/bugs/show_bug.cgi?id=226401 |
| *******************************************************************************/ |
| package org.eclipse.equinox.internal.p2.director.app; |
| |
| import java.io.File; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| 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.console.ProvisioningHelper; |
| import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; |
| import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; |
| import org.eclipse.equinox.internal.provisional.p2.director.*; |
| import org.eclipse.equinox.internal.provisional.p2.engine.*; |
| import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; |
| import org.eclipse.equinox.internal.provisional.p2.metadata.query.InstallableUnitQuery; |
| import org.eclipse.equinox.internal.provisional.p2.query.Collector; |
| import org.eclipse.osgi.service.resolver.VersionRange; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.*; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| |
| public class Application implements IApplication { |
| private static final Integer EXIT_ERROR = new Integer(13); |
| static private String FLAVOR_DEFAULT = "tooling"; //$NON-NLS-1$ |
| static private String EXEMPLARY_SETUP = "org.eclipse.equinox.p2.exemplarysetup"; //$NON-NLS-1$ |
| static private String FRAMEWORKADMIN_EQUINOX = "org.eclipse.equinox.frameworkadmin.equinox"; //$NON-NLS-1$ |
| static private String SIMPLE_CONFIGURATOR_MANIPULATOR = "org.eclipse.equinox.simpleconfigurator.manipulator"; //$NON-NLS-1$ |
| |
| public static final int COMMAND_INSTALL = 0; |
| public static final int COMMAND_UNINSTALL = 1; |
| public static final int COMMAND_LIST = 2; |
| |
| public static final String[] COMMAND_NAMES = {"-installIU", "-uninstallIU", "-list"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| |
| // private ServiceRegistration directorRegistration; |
| // private ServiceRegistration plannerRegistration; |
| // private ServiceRegistration engineRegistration; |
| // private ServiceRegistration busRegistration; |
| // private ServiceRegistration metadataManagerRegistration; |
| // private ServiceRegistration artifactManagerRegistration; |
| // private IProvisioningEventBus bus; |
| |
| private Path destination; |
| |
| private URL[] artifactRepositoryLocations; |
| |
| private URL[] metadataRepositoryLocations; |
| |
| private String root; |
| private Version version = null; |
| private String flavor; |
| private String profileId; |
| private String profileProperties; // a comma-separated list of property pairs "tag=value" |
| private String bundlePool = null; |
| private String nl; |
| private String os; |
| private String arch; |
| private String ws; |
| private boolean roamingProfile = false; |
| private IPlanner planner; |
| private IEngine engine; |
| |
| private int command = -1; |
| |
| private ServiceReference packageAdminRef; |
| private PackageAdmin packageAdmin; |
| private boolean needsToUpdateRoamingValues = false; |
| |
| private void ambigousCommand(int cmd1, int cmd2) throws CoreException { |
| throw new CoreException(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Ambigous_Command, new Object[] {COMMAND_NAMES[cmd1], COMMAND_NAMES[cmd2]}))); |
| } |
| |
| private ProfileChangeRequest buildProvisioningRequest(IProfile profile, Collector roots, boolean install) { |
| ProfileChangeRequest request = new ProfileChangeRequest(profile); |
| markRoots(request, roots); |
| if (install) { |
| request.addInstallableUnits((IInstallableUnit[]) roots.toArray(IInstallableUnit.class)); |
| } else { |
| request.removeInstallableUnits((IInstallableUnit[]) roots.toArray(IInstallableUnit.class)); |
| } |
| return request; |
| } |
| |
| synchronized Bundle getBundle(String symbolicName) { |
| if (packageAdmin == null) |
| return null; |
| |
| Bundle[] bundles = packageAdmin.getBundles(symbolicName, null); |
| if (bundles == null) |
| return null; |
| //Return the first bundle that is not installed or uninstalled |
| for (int i = 0; i < bundles.length; i++) { |
| if ((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) { |
| return bundles[i]; |
| } |
| } |
| return null; |
| } |
| |
| private String getEnvironmentProperty() { |
| Properties values = new Properties(); |
| 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$ |
| if (values.isEmpty()) |
| return null; |
| return toString(values); |
| } |
| |
| private IProfile initializeProfile() throws CoreException { |
| if (profileId == null) |
| profileId = IProfileRegistry.SELF; |
| IProfile profile = ProvisioningHelper.getProfile(profileId); |
| if (profile != null && (ProvisioningHelper.getProfile(IProfileRegistry.SELF) != null && !profile.getProfileId().equals(ProvisioningHelper.getProfile(IProfileRegistry.SELF).getProfileId()))) |
| needsToUpdateRoamingValues = true; |
| 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$ |
| |
| Properties props = new Properties(); |
| props.setProperty(IProfile.PROP_INSTALL_FOLDER, destination.toOSString()); |
| props.setProperty(IProfile.PROP_FLAVOR, flavor); |
| if (bundlePool != null) |
| if (bundlePool.equals(Messages.destination_commandline)) |
| props.setProperty(IProfile.PROP_CACHE, destination.toOSString()); |
| else |
| props.setProperty(IProfile.PROP_CACHE, bundlePool); |
| if (roamingProfile) |
| props.setProperty(IProfile.PROP_ROAMING, Boolean.TRUE.toString()); |
| |
| String env = getEnvironmentProperty(); |
| if (env != null) |
| props.setProperty(IProfile.PROP_ENVIRONMENTS, env); |
| if (profileProperties != null) { |
| putProperties(profileProperties, props); |
| } |
| profile = ProvisioningHelper.addProfile(profileId, props); |
| String currentFlavor = profile.getProperty(IProfile.PROP_FLAVOR); |
| if (currentFlavor != null && !currentFlavor.endsWith(flavor)) |
| throw new RuntimeException(Messages.Inconsistent_flavor); |
| } |
| return profile; |
| } |
| |
| private void initializeRepositories(boolean throwException) throws CoreException { |
| if (artifactRepositoryLocations == null) { |
| if (throwException) |
| missingArgument("artifactRepository"); //$NON-NLS-1$ |
| } else { |
| for (int i = 0; i < artifactRepositoryLocations.length; i++) |
| ProvisioningHelper.addArtifactRepository(artifactRepositoryLocations[i]); |
| } |
| |
| if (metadataRepositoryLocations == null) { |
| if (throwException) |
| missingArgument("metadataRepository"); //$NON-NLS-1$ |
| } else { |
| for (int i = 0; i < metadataRepositoryLocations.length; i++) |
| ProvisioningHelper.addMetadataRepository(metadataRepositoryLocations[i]); |
| } |
| } |
| |
| private void initializeServices() { |
| IDirector director = (IDirector) ServiceHelper.getService(Activator.getContext(), IDirector.class.getName()); |
| if (director == null) |
| throw new RuntimeException(Messages.Missing_director); |
| |
| planner = (IPlanner) ServiceHelper.getService(Activator.getContext(), IPlanner.class.getName()); |
| if (planner == null) |
| throw new RuntimeException(Messages.Missing_planner); |
| |
| engine = (IEngine) ServiceHelper.getService(Activator.getContext(), IEngine.SERVICE_NAME); |
| if (engine == null) |
| throw new RuntimeException(Messages.Missing_Engine); |
| } |
| |
| private void markRoots(ProfileChangeRequest request, Collector roots) { |
| for (Iterator iterator = roots.iterator(); iterator.hasNext();) { |
| request.setInstallableUnitProfileProperty((IInstallableUnit) iterator.next(), IInstallableUnit.PROP_PROFILE_ROOT_IU, Boolean.TRUE.toString()); |
| } |
| } |
| |
| private void missingArgument(String argumentName) throws CoreException { |
| throw new CoreException(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_Required_Argument, argumentName))); |
| } |
| |
| private IStatus planAndExecute(IProfile profile, ProvisioningContext context, ProfileChangeRequest request) { |
| ProvisioningPlan result; |
| IStatus operationStatus; |
| result = planner.getProvisioningPlan(request, context, new NullProgressMonitor()); |
| if (!result.getStatus().isOK()) |
| operationStatus = result.getStatus(); |
| else { |
| operationStatus = engine.perform(profile, new DefaultPhaseSet(), result.getOperands(), context, new NullProgressMonitor()); |
| } |
| return operationStatus; |
| } |
| |
| private void printRequest(ProfileChangeRequest request) { |
| IInstallableUnit[] toAdd = request.getAddedInstallableUnits(); |
| IInstallableUnit[] toRemove = request.getRemovedInstallableUnits(); |
| for (int i = 0; i < toAdd.length; i++) { |
| System.out.println(NLS.bind(Messages.Installing, toAdd[i].getId(), toAdd[i].getVersion())); |
| } |
| for (int i = 0; i < toRemove.length; i++) { |
| System.out.println(NLS.bind(Messages.Uninstalling, toRemove[i].getId(), toRemove[i].getVersion())); |
| } |
| } |
| |
| public void processArguments(String[] args) throws Exception { |
| if (args == null) |
| return; |
| for (int i = 0; i < args.length; i++) { |
| |
| String opt = args[i]; |
| if (opt.equals("-roaming")) { //$NON-NLS-1$ |
| roamingProfile = true; |
| } |
| |
| if (opt.equals(COMMAND_NAMES[COMMAND_LIST])) { |
| if (command != -1) |
| ambigousCommand(COMMAND_LIST, command); |
| command = COMMAND_LIST; |
| } |
| |
| // check for args without parameters (i.e., a flag arg) |
| |
| // 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 parm so continue. |
| if (i == args.length - 1 || args[i + 1].startsWith("-")) //$NON-NLS-1$ |
| continue; |
| |
| String arg = args[++i]; |
| |
| if (opt.equalsIgnoreCase("-profile")) //$NON-NLS-1$ |
| profileId = arg; |
| |
| if (opt.equalsIgnoreCase("-profileProperties") || opt.equalsIgnoreCase("-props")) //$NON-NLS-1$ //$NON-NLS-2$ |
| profileProperties = arg; |
| |
| // we create a path object here to handle ../ entries in the middle of paths |
| if (opt.equalsIgnoreCase("-destination") || opt.equalsIgnoreCase("-dest")) //$NON-NLS-1$ //$NON-NLS-2$ |
| destination = new Path(arg); |
| |
| // we create a path object here to handle ../ entries in the middle of paths |
| if (opt.equalsIgnoreCase("-bundlepool") || opt.equalsIgnoreCase("-bp")) //$NON-NLS-1$ //$NON-NLS-2$ |
| bundlePool = new Path(arg).toOSString(); |
| |
| if (opt.equalsIgnoreCase("-metadataRepository") || opt.equalsIgnoreCase("-metadataRepositories") || opt.equalsIgnoreCase("-mr")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| metadataRepositoryLocations = getURLs(arg); |
| |
| if (opt.equalsIgnoreCase("-artifactRepository") || opt.equalsIgnoreCase("-artifactRepositories") || opt.equalsIgnoreCase("-ar")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| artifactRepositoryLocations = getURLs(arg); |
| |
| if (opt.equalsIgnoreCase("-flavor")) //$NON-NLS-1$ |
| flavor = arg; |
| |
| if (opt.equalsIgnoreCase(COMMAND_NAMES[COMMAND_INSTALL])) { |
| if (command != -1) |
| ambigousCommand(COMMAND_INSTALL, command); |
| root = arg; |
| command = COMMAND_INSTALL; |
| } |
| |
| if (opt.equalsIgnoreCase("-version")) { //$NON-NLS-1$ |
| version = new Version(arg); |
| } |
| |
| if (opt.equalsIgnoreCase(COMMAND_NAMES[COMMAND_UNINSTALL])) { |
| if (command != -1) |
| ambigousCommand(COMMAND_UNINSTALL, command); |
| root = arg; |
| command = COMMAND_UNINSTALL; |
| } |
| |
| if (opt.equalsIgnoreCase("-p2.os")) { //$NON-NLS-1$ |
| os = arg; |
| } |
| if (opt.equalsIgnoreCase("-p2.ws")) { //$NON-NLS-1$ |
| ws = arg; |
| } |
| if (opt.equalsIgnoreCase("-p2.nl")) { //$NON-NLS-1$ |
| nl = arg; |
| } |
| if (opt.equalsIgnoreCase("-p2.arch")) { //$NON-NLS-1$ |
| arch = arg; |
| } |
| } |
| |
| } |
| |
| /** |
| * @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, Properties properties) { |
| StringTokenizer tok = new StringTokenizer(pairs, ",", true); //$NON-NLS-1$ |
| while (tok.hasMoreTokens()) { |
| String next = tok.nextToken().trim(); |
| int i = next.indexOf('='); |
| if (i > 0 && i < next.length() - 1) { |
| String tag = next.substring(0, i).trim(); |
| String value = next.substring(i + 1, next.length()).trim(); |
| if (tag.length() > 0 && value.length() > 0) { |
| properties.put(tag, value); |
| } |
| } |
| } |
| } |
| |
| public Object run(String[] args) throws Exception { |
| long time = -System.currentTimeMillis(); |
| initializeServices(); |
| processArguments(args); |
| |
| IStatus operationStatus = Status.OK_STATUS; |
| InstallableUnitQuery query; |
| Collector roots; |
| switch (command) { |
| case COMMAND_INSTALL : |
| case COMMAND_UNINSTALL : |
| initializeRepositories(command == COMMAND_INSTALL); |
| |
| IProfile profile = initializeProfile(); |
| query = new InstallableUnitQuery(root, version == null ? VersionRange.emptyRange : new VersionRange(version, true, version, true)); |
| roots = ProvisioningHelper.getInstallableUnits(null, query, new LatestIUVersionCollector(), new NullProgressMonitor()); |
| if (roots.size() <= 0) |
| roots = profile.query(query, roots, new NullProgressMonitor()); |
| if (roots.size() <= 0) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_IU, root))); |
| System.out.println(NLS.bind(Messages.Missing_IU, root)); |
| return EXIT_ERROR; |
| } |
| if (!updateRoamingProperties(profile).isOK()) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Cant_change_roaming, profile.getProfileId()))); |
| System.out.println(NLS.bind(Messages.Cant_change_roaming, profile.getProfileId())); |
| return EXIT_ERROR; |
| } |
| ProvisioningContext context = new ProvisioningContext(); |
| ProfileChangeRequest request = buildProvisioningRequest(profile, roots, command == COMMAND_INSTALL); |
| printRequest(request); |
| operationStatus = planAndExecute(profile, context, request); |
| break; |
| case COMMAND_LIST : |
| query = new InstallableUnitQuery(null, VersionRange.emptyRange); |
| if (metadataRepositoryLocations == null) |
| missingArgument("metadataRepository"); //$NON-NLS-1$ |
| |
| for (int i = 0; i < metadataRepositoryLocations.length; i++) { |
| roots = ProvisioningHelper.getInstallableUnits(metadataRepositoryLocations[i], query, new NullProgressMonitor()); |
| |
| Iterator unitIterator = roots.iterator(); |
| while (unitIterator.hasNext()) { |
| IInstallableUnit iu = (IInstallableUnit) unitIterator.next(); |
| System.out.println(iu.getId()); |
| } |
| } |
| break; |
| } |
| |
| time += System.currentTimeMillis(); |
| if (operationStatus.isOK()) |
| System.out.println(NLS.bind(Messages.Operation_complete, new Long(time))); |
| else { |
| System.out.println(Messages.Operation_failed); |
| LogHelper.log(operationStatus); |
| return EXIT_ERROR; |
| } |
| return IApplication.EXIT_OK; |
| } |
| |
| private synchronized void setPackageAdmin(PackageAdmin service) { |
| packageAdmin = service; |
| } |
| |
| private boolean startEarly(String bundleName) throws BundleException { |
| Bundle bundle = getBundle(bundleName); |
| if (bundle == null) |
| return false; |
| bundle.start(Bundle.START_TRANSIENT); |
| return true; |
| } |
| |
| public Object start(IApplicationContext context) throws Exception { |
| packageAdminRef = Activator.getContext().getServiceReference(PackageAdmin.class.getName()); |
| setPackageAdmin((PackageAdmin) Activator.getContext().getService(packageAdminRef)); |
| if (!startEarly(EXEMPLARY_SETUP)) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_bundle, EXEMPLARY_SETUP))); |
| return EXIT_ERROR; |
| } |
| if (!startEarly(SIMPLE_CONFIGURATOR_MANIPULATOR)) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_bundle, SIMPLE_CONFIGURATOR_MANIPULATOR))); |
| return EXIT_ERROR; |
| } |
| if (!startEarly(FRAMEWORKADMIN_EQUINOX)) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Missing_bundle, FRAMEWORKADMIN_EQUINOX))); |
| return EXIT_ERROR; |
| } |
| |
| return run((String[]) context.getArguments().get("application.args")); //$NON-NLS-1$ |
| } |
| |
| public void stop() { |
| setPackageAdmin(null); |
| Activator.getContext().ungetService(packageAdminRef); |
| } |
| |
| private String toString(Properties context) { |
| StringBuffer result = new StringBuffer(); |
| for (Enumeration iter = context.keys(); iter.hasMoreElements();) { |
| String key = (String) iter.nextElement(); |
| result.append(key); |
| result.append('='); |
| result.append(context.get(key)); |
| if (iter.hasMoreElements()) |
| result.append(','); |
| } |
| return result.toString(); |
| } |
| |
| private IStatus updateRoamingProperties(IProfile profile) { |
| if (!needsToUpdateRoamingValues) |
| return Status.OK_STATUS; |
| ProfileChangeRequest request = new ProfileChangeRequest(profile); |
| if (!Boolean.valueOf(profile.getProperty(IProfile.PROP_ROAMING)).booleanValue()) |
| return Status.OK_STATUS; |
| if (!destination.equals(new File(profile.getProperty(IProfile.PROP_INSTALL_FOLDER)))) { |
| request.setProfileProperty(IProfile.PROP_INSTALL_FOLDER, destination.toOSString()); |
| } |
| if (!destination.equals(new File(profile.getProperty(IProfile.PROP_CACHE)))) { |
| request.setProfileProperty(IProfile.PROP_CACHE, destination.toOSString()); |
| } |
| if (request.getProfileProperties().size() == 0) |
| return Status.OK_STATUS; |
| |
| ProvisioningPlan result = planner.getProvisioningPlan(request, new ProvisioningContext(), new NullProgressMonitor()); |
| if (!result.getStatus().isOK()) |
| return result.getStatus(); |
| |
| return engine.perform(profile, new DefaultPhaseSet(), result.getOperands(), new ProvisioningContext(), new NullProgressMonitor()); |
| } |
| |
| private static URL[] getURLs(String spec) { |
| if (spec == null) |
| return null; |
| String[] urlSpecs = getArrayFromString(spec, ","); //$NON-NLS-1$ |
| ArrayList result = new ArrayList(urlSpecs.length); |
| for (int i = 0; i < urlSpecs.length; i++) { |
| try { |
| result.add(new URL(urlSpecs[i])); |
| } catch (MalformedURLException e) { |
| NLS.bind(Messages.Ignored_repo, urlSpecs[i]); |
| } |
| } |
| return (URL[]) result.toArray(new URL[result.size()]); |
| } |
| |
| /** |
| * Convert a list of tokens into an array. The list separator has to be |
| * specified. |
| */ |
| public static String[] getArrayFromString(String list, String separator) { |
| if (list == null || list.trim().equals("")) //$NON-NLS-1$ |
| return new String[0]; |
| List result = new ArrayList(); |
| for (StringTokenizer tokens = new StringTokenizer(list, separator); tokens.hasMoreTokens();) { |
| String token = tokens.nextToken().trim(); |
| if (!token.equals("")) //$NON-NLS-1$ |
| result.add(token); |
| } |
| return (String[]) result.toArray(new String[result.size()]); |
| } |
| |
| } |