1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 IBM Corporation and others.
\r
3 * All rights reserved. This program and the accompanying materials
\r
4 * are made available under the terms of the Eclipse Public License v1.0
\r
5 * which accompanies this distribution, and is available at
\r
6 * http://www.eclipse.org/legal/epl-v10.html
\r
9 * IBM Corporation - initial API and implementation
\r
10 * Code 9 - ongoing development
\r
11 * Sonatype, Inc. - ongoing development
\r
12 *******************************************************************************/
\r
13 package org.simantics.project.management.install;
\r
15 import java.net.URI;
\r
16 import java.util.ArrayList;
\r
17 import java.util.Collection;
\r
18 import java.util.HashMap;
\r
19 import java.util.Iterator;
\r
20 import java.util.Map;
\r
22 import org.eclipse.core.runtime.CoreException;
\r
23 import org.eclipse.core.runtime.IPath;
\r
24 import org.eclipse.core.runtime.IProgressMonitor;
\r
25 import org.eclipse.core.runtime.IStatus;
\r
26 import org.eclipse.core.runtime.Status;
\r
27 import org.eclipse.core.runtime.SubMonitor;
\r
28 import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
\r
29 import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
\r
30 import org.eclipse.equinox.internal.provisional.p2.director.IDirector;
\r
31 import org.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation;
\r
32 import org.eclipse.equinox.internal.provisional.p2.installer.InstallDescription;
\r
33 import org.eclipse.equinox.p2.core.IProvisioningAgent;
\r
34 import org.eclipse.equinox.p2.core.ProvisionException;
\r
35 import org.eclipse.equinox.p2.engine.IProfile;
\r
36 import org.eclipse.equinox.p2.engine.IProfileRegistry;
\r
37 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
\r
38 import org.eclipse.equinox.p2.metadata.IVersionedId;
\r
39 import org.eclipse.equinox.p2.metadata.Version;
\r
40 import org.eclipse.equinox.p2.metadata.VersionRange;
\r
41 import org.eclipse.equinox.p2.query.IQuery;
\r
42 import org.eclipse.equinox.p2.query.IQueryResult;
\r
43 import org.eclipse.equinox.p2.query.QueryUtil;
\r
44 import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
\r
45 import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
\r
46 import org.eclipse.osgi.service.environment.EnvironmentInfo;
\r
47 import org.eclipse.osgi.util.NLS;
\r
48 import org.simantics.project.internal.Activator;
\r
51 * This operation performs installation or update of an Eclipse-based product.
\r
53 @SuppressWarnings("restriction")
\r
54 public class InstallUpdateProductOperation implements IInstallOperation {
\r
56 private IArtifactRepositoryManager artifactRepoMan;
\r
57 private IProvisioningAgent agent;
\r
58 private IDirector director;
\r
59 private final InstallDescription installDescription;
\r
60 private boolean isInstall = true;
\r
61 private IMetadataRepositoryManager metadataRepoMan;
\r
62 private IProfileRegistry profileRegistry;
\r
63 private IStatus result;
\r
65 public InstallUpdateProductOperation(IProvisioningAgent agent, InstallDescription description) {
\r
67 this.installDescription = description;
\r
71 * Determine what top level installable units should be installed by the director
\r
73 private Collection<IInstallableUnit> computeUnitsToInstall() throws CoreException {
\r
74 ArrayList<IInstallableUnit> units = new ArrayList<IInstallableUnit>();
\r
75 IVersionedId roots[] = installDescription.getRoots();
\r
76 for (int i = 0; i < roots.length; i++) {
\r
77 IVersionedId root = roots[i];
\r
78 IInstallableUnit iu = findUnit(root);
\r
86 * This profile is being updated; return the units to uninstall from the profile.
\r
88 private IQueryResult<IInstallableUnit> computeUnitsToUninstall(IProfile p) {
\r
89 return p.query(QueryUtil.createIUAnyQuery(), null);
\r
93 * Create and return the profile into which units will be installed.
\r
95 private IProfile createProfile() throws ProvisionException {
\r
96 IProfile profile = getProfile();
\r
97 if (profile == null) {
\r
98 Map<String, String> properties = new HashMap<String, String>();
\r
99 properties.put(IProfile.PROP_INSTALL_FOLDER, installDescription.getInstallLocation().toString());
\r
100 EnvironmentInfo info = (EnvironmentInfo) ServiceHelper.getService(Activator.getDefault().getBundle().getBundleContext(), EnvironmentInfo.class.getName());
\r
101 String env = "osgi.os=" + info.getOS() + ",osgi.ws=" + info.getWS() + ",osgi.arch=" + info.getOSArch(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
\r
102 properties.put(IProfile.PROP_ENVIRONMENTS, env);
\r
103 properties.put(IProfile.PROP_NAME, installDescription.getProductName());
\r
104 properties.putAll(installDescription.getProfileProperties());
\r
105 IPath location = installDescription.getBundleLocation();
\r
106 if (location != null)
\r
107 properties.put(IProfile.PROP_CACHE, location.toOSString());
\r
108 profile = profileRegistry.addProfile(getProfileId(), properties);
\r
114 * Performs the actual product install or update.
\r
116 private void doInstall(SubMonitor monitor) throws CoreException {
\r
117 prepareMetadataRepositories();
\r
118 prepareArtifactRepositories();
\r
119 IProfile p = createProfile();
\r
120 Collection<IInstallableUnit> toInstall = computeUnitsToInstall();
\r
124 ProfileChangeRequest request = new ProfileChangeRequest(p);
\r
126 monitor.setTaskName(NLS.bind("Installing", installDescription.getProductName()));
\r
127 request.addAll(toInstall);
\r
128 s = director.provision(request, null, monitor.newChild(90));
\r
130 monitor.setTaskName(NLS.bind("Updating", installDescription.getProductName()));
\r
131 IQueryResult<IInstallableUnit> toUninstall = computeUnitsToUninstall(p);
\r
132 request.removeAll(toUninstall.toUnmodifiableSet());
\r
133 request.addAll(toInstall);
\r
134 s = director.provision(request, null, monitor.newChild(90));
\r
137 throw new CoreException(s);
\r
141 * Returns an exception of severity error with the given error message.
\r
143 private CoreException fail(String message) {
\r
144 return fail(message, null);
\r
148 * Returns an exception of severity error with the given error message.
\r
150 private CoreException fail(String message, Throwable throwable) {
\r
151 return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, throwable));
\r
155 * Finds and returns the installable unit with the given id, and optionally the
\r
158 private IInstallableUnit findUnit(IVersionedId spec) throws CoreException {
\r
159 String id = spec.getId();
\r
161 throw fail("No id");
\r
162 Version version = spec.getVersion();
\r
163 VersionRange range = VersionRange.emptyRange;
\r
164 if (version != null && !version.equals(Version.emptyVersion))
\r
165 range = new VersionRange(version, true, version, true);
\r
166 IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(id, range);
\r
167 Iterator<IInstallableUnit> matches = metadataRepoMan.query(query, null).iterator();
\r
168 // pick the newest match
\r
169 IInstallableUnit newest = null;
\r
170 while (matches.hasNext()) {
\r
171 IInstallableUnit candidate = matches.next();
\r
172 if (newest == null || (newest.getVersion().compareTo(candidate.getVersion()) < 0))
\r
173 newest = candidate;
\r
175 if (newest == null)
\r
176 throw fail("IU not found " + id);
\r
181 * Returns the profile being installed into.
\r
183 private IProfile getProfile() {
\r
184 return profileRegistry.getProfile(getProfileId());
\r
188 * Returns the id of the profile to use for install/update based on this operation's install description.
\r
190 private String getProfileId() {
\r
191 IPath location = installDescription.getInstallLocation();
\r
192 if (location != null)
\r
193 return location.toString();
\r
194 return installDescription.getProductName();
\r
198 * Returns the result of the install operation, or <code>null</code> if
\r
199 * no install operation has been run.
\r
201 public IStatus getResult() {
\r
205 private Object getService(String name) throws CoreException {
\r
206 Object service = agent.getService(name);
\r
207 if (service == null)
\r
208 throw fail("No service " + name);
\r
213 * @see org.eclipse.equinox.internal.provisional.p2.installer.IInstallOperation#install(org.eclipse.core.runtime.IProgressMonitor)
\r
215 public IStatus install(IProgressMonitor pm) {
\r
216 SubMonitor monitor = SubMonitor.convert(pm, "Preparing", 100);
\r
220 isInstall = getProfile() == null;
\r
221 doInstall(monitor);
\r
222 result = new Status(IStatus.OK, Activator.PLUGIN_ID, isInstall ? "Install Complete" : "Update Complete", null);
\r
223 monitor.setTaskName("Cleanup");
\r
227 } catch (CoreException e) {
\r
228 result = e.getStatus();
\r
236 * Returns whether this operation represents the product being installed
\r
237 * for the first time, in a new profile.
\r
239 public boolean isFirstInstall() {
\r
243 private void postInstall() {
\r
247 private void preInstall() throws CoreException {
\r
248 //obtain required services
\r
249 director = (IDirector) getService(IDirector.SERVICE_NAME);
\r
250 metadataRepoMan = (IMetadataRepositoryManager) getService(IMetadataRepositoryManager.SERVICE_NAME);
\r
251 artifactRepoMan = (IArtifactRepositoryManager) getService(IArtifactRepositoryManager.SERVICE_NAME);
\r
252 profileRegistry = (IProfileRegistry) getService(IProfileRegistry.SERVICE_NAME);
\r
255 private void prepareArtifactRepositories() throws ProvisionException {
\r
256 URI[] repos = installDescription.getArtifactRepositories();
\r
260 // Repositories must be registered before they are loaded
\r
261 // This is to avoid them being possibly overridden with the configuration as a referenced repository
\r
262 for (int i = 0; i < repos.length; i++) {
\r
263 artifactRepoMan.addRepository(repos[i]);
\r
264 artifactRepoMan.loadRepository(repos[i], null);
\r
268 private void prepareMetadataRepositories() throws ProvisionException {
\r
269 URI[] repos = installDescription.getMetadataRepositories();
\r
273 // Repositories must be registered before they are loaded
\r
274 // This is to avoid them being possibly overridden with the configuration as a referenced repository
\r
275 for (int i = 0; i < repos.length; i++) {
\r
276 metadataRepoMan.addRepository(repos[i]);
\r
277 metadataRepoMan.loadRepository(repos[i], null);
\r