/******************************************************************************* * Copyright (c) 2014 Mentor Graphics 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: * Mentor Graphics - initial API and implementation *******************************************************************************/ package com.codesourcery.internal.installer.actions; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.equinox.internal.p2.touchpoint.eclipse.actions.ActionConstants; import org.eclipse.equinox.internal.p2.touchpoint.eclipse.actions.AddRepositoryAction; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IVersionedId; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.IRepository; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.codesourcery.installer.IInstallMode; import com.codesourcery.installer.IInstallProduct; import com.codesourcery.installer.Installer; import com.codesourcery.installer.UpdateSite; import com.codesourcery.installer.actions.AbstractInstallAction; import com.codesourcery.internal.installer.InstallMessages; import com.codesourcery.internal.installer.RepositoryManager; /** * Action to install/uninstall p2 installable units. */ @SuppressWarnings("restriction") // Accesses internal p2 API's public class InstallIUAction extends AbstractInstallAction { /** Action identifier */ private static final String ID = "com.codesourcery.installer.installIUAction"; /** Profile attribute */ private static final String ATTRIBUTE_PROFILE = "profile"; /** Remove profile attribute */ private static final String ATTRIBUTE_REMOVE_PROFILE = "removeProfile"; /** Units to install */ private IInstallableUnit[] unitsToInstall; /** Units to uninstall */ private IInstallableUnit[] unitsToUninstall; /** Profile for operation */ private String profileName; /** Update sites */ private UpdateSite[] updateSites; /** Profile properties */ private Map<String, String> profileProperties; /** <code>true</code> to remove profile on uninstallation */ private boolean removeProfile; /** * Required no argument constructor. */ public InstallIUAction() { super(ID); } /** * Constructor for install operation * * @param profileName Profile name * @param profileProperties Profile properties * @param productName Product name * @param updateSites Update sites or <code>null</code> * @param unitsToInstall Roots to install or <code>null</code> * @param unitsToUninstall Roots to uninstall or <code>null</code> */ public InstallIUAction(String profileName, Map<String, String> profileProperties, UpdateSite[] updateSites, IInstallableUnit[] unitsToInstall, IInstallableUnit[] unitsToUninstall) { super(ID); this.profileName = profileName; this.updateSites = updateSites; this.unitsToInstall = unitsToInstall; this.unitsToUninstall = unitsToUninstall; this.profileProperties = profileProperties; } /** * Sets the profile to be removed on uninstallation. * * @param removeProfile <code>true</code> to remove profile */ public void setRemoveProfile(boolean removeProfile) { this.removeProfile = removeProfile; } /** * Returns if the profile will be removed on uninstallation. * * @return <code>true</code> to remove profile */ public boolean getRemoveProfile() { return removeProfile; } /** * Returns the profile name. * * @return Profile name */ public String getProfileName() { return profileName; } /** * Returns the roots to install. * * @return Roots or <code>null</code> */ public IInstallableUnit[] getRootsToInstall() { return unitsToInstall; } /** * Returns roots to uninstall. * * @return Roots or <code>null</code> */ public IInstallableUnit[] getRootsToUninstall() { return unitsToUninstall; } /** * Returns the update sites. * * @return Update sites or <code>null</code> */ public UpdateSite[] getUpdateSites() { return updateSites; } /** * Returns the profile properties. * * @return Profile properties */ public Map<String, String> getProfileProperties() { return profileProperties; } @Override public int getProgressWeight() { final int SCALE = 100; int weight = 0; if (getRootsToInstall() != null) { weight += getRootsToInstall().length * DEFAULT_PROGRESS_WEIGHT * SCALE; } if (getRootsToUninstall() != null) { weight += getRootsToInstall().length * DEFAULT_PROGRESS_WEIGHT * SCALE; } if (weight == 0) { weight = DEFAULT_PROGRESS_WEIGHT * SCALE; } return weight; } @Override public void run(IProvisioningAgent agent, IInstallProduct product, IInstallMode mode, IProgressMonitor monitor) throws CoreException { try { ArrayList<IInstallableUnit> toAdd = new ArrayList<IInstallableUnit>(); ArrayList<IInstallableUnit> toRemove = new ArrayList<IInstallableUnit>(); IProfile profile = RepositoryManager.getDefault().getProfile(getProfileName()); // Install if (mode.isInstall()) { // Units to add if (getRootsToInstall() != null) { toAdd.addAll(Arrays.asList(getRootsToInstall())); } // Units to remove if (getRootsToUninstall() != null) { toRemove.addAll(Arrays.asList(getRootsToUninstall())); } if (!toAdd.isEmpty() || !toRemove.isEmpty()) { RepositoryManager.getDefault().provision(profile, toAdd, toRemove, true, monitor); } // Add units to product for (IInstallableUnit unit : toAdd) { product.addInstallUnit(unit); } // Remove units from product for (IInstallableUnit unit : toRemove) { product.removeInstallUnit(unit); } // Add any update sites if (!mode.isUpdate() && !mode.isUpgrade()) { UpdateSite[] updateSites = getUpdateSites(); if (updateSites != null) { for (UpdateSite updateSite : updateSites) { AddRepositoryAction action = new AddRepositoryAction(); HashMap<String, Object> params = new HashMap<String, Object>(); params.put("agent", agent); params.put(ActionConstants.PARM_PROFILE, getProfileName()); params.put(ActionConstants.PARM_REPOSITORY_LOCATION, updateSite.getLocation()); params.put(ActionConstants.PARM_REPOSITORY_TYPE, Integer.toString(IRepository.TYPE_METADATA)); if (updateSite.getName() != null) params.put(ActionConstants.PARM_REPOSITORY_NICKNAME, updateSite.getName()); action.execute(params); params.put(ActionConstants.PARM_REPOSITORY_TYPE, Integer.toString(IRepository.TYPE_ARTIFACT)); action.execute(params); } } } } // Uninstall else { String propRemoveDirs = product.getProperty(IInstallProduct.PROPERTY_REMOVE_DIRS); boolean removeDirs = ((propRemoveDirs == null) || Boolean.parseBoolean(propRemoveDirs)); // Optimization: If there are no more products and the installation directory is // being removed, there is no need to unprovision install units. if ((Installer.getDefault().getInstallManager().getInstallManifest().getProducts().length != 0) || !removeDirs){ // Remove all units in profile if (getRemoveProfile()) { IQueryResult<IInstallableUnit> query = profile.query(QueryUtil.createIUAnyQuery(), null); Iterator<IInstallableUnit> i = query.iterator(); while (i.hasNext()) { toRemove.add(i.next()); } } // Or remove only units that were installed else { IVersionedId[] productUnits = product.getInstallUnits(); // Get installable units to uninstall for (IVersionedId unit : productUnits) { IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(unit); IQueryResult<IInstallableUnit> roots = profile.query(query, new NullProgressMonitor()); Iterator<IInstallableUnit> iter = roots.iterator(); while (iter.hasNext()) { IInstallableUnit iu = iter.next(); toRemove.add(iu); } } } RepositoryManager.getDefault().provision(profile, null, toRemove, true, monitor); } } } catch (Exception e) { if (e instanceof CoreException) throw e; else Installer.fail(InstallMessages.Error_FailedToInstall, e); } finally { monitor.done(); } } @Override public void save(Document document, Element node) throws CoreException { node.setAttribute(ATTRIBUTE_PROFILE, getProfileName()); node.setAttribute(ATTRIBUTE_REMOVE_PROFILE, Boolean.toString(getRemoveProfile())); } @Override public void load(Element element) throws CoreException { profileName = element.getAttribute(ATTRIBUTE_PROFILE); String propRemoveProfile = element.getAttribute(ATTRIBUTE_REMOVE_PROFILE); if (propRemoveProfile != null) { setRemoveProfile(Boolean.parseBoolean(propRemoveProfile)); } } /** * Copied from ServiceHelper because we need to obtain services * before p2 has been started. */ public static Object getService(BundleContext context, String name) { if (context == null) return null; ServiceReference<?> reference = context.getServiceReference(name); if (reference == null) return null; Object result = context.getService(reference); context.ungetService(reference); return result; } @Override public boolean uninstallOnUpgrade() { // Removeal of installable units on an upgrade will be handled // during install because we might be replacing units that other // units are dependent on. return false; } }