blob: 9b5d42ae7aa830d36cc2cfecdd6432046d67ed78 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2009 Code 9 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:
* Code 9 - initial API and implementation
* IBM - ongoing development
******************************************************************************/
package org.eclipse.equinox.p2.publisher.eclipse;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import java.io.File;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.FileUtils;
import org.eclipse.equinox.internal.p2.publisher.eclipse.BrandingIron;
import org.eclipse.equinox.internal.p2.publisher.eclipse.ExecutablesDescriptor;
import org.eclipse.equinox.internal.provisional.p2.metadata.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory.InstallableUnitDescription;
import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory.InstallableUnitFragmentDescription;
import org.eclipse.equinox.p2.publisher.*;
import org.eclipse.equinox.p2.repository.artifact.IArtifactDescriptor;
import org.eclipse.equinox.spi.p2.publisher.PublisherHelper;
import org.eclipse.osgi.service.environment.Constants;
/**
* Given the description of an executable, this action publishes optionally
* non-destructively brands the executable, publishes the resultant artifacts
* and publishes the required IUs to identify the branded executable, configure
* the executable and set it up as the launcher for a profile.
* <p>
* This action works on one platform configuration only.
* <p>
* This action consults the following types of advice:
* </ul>
* <li>{@link IBrandingAdvice}</li>
* </ul>
*/
public class EquinoxExecutableAction extends AbstractPublisherAction {
private static String TYPE = "executable"; //$NON-NLS-1$
protected String configSpec;
protected String idBase;
protected Version version;
protected ExecutablesDescriptor executables;
protected String flavor;
protected EquinoxExecutableAction() {
//hidden
}
public EquinoxExecutableAction(ExecutablesDescriptor executables, String configSpec, String idBase, Version version, String flavor) {
this.executables = executables;
this.configSpec = configSpec;
this.idBase = idBase == null ? "org.eclipse" : idBase; //$NON-NLS-1$
this.version = version;
this.flavor = flavor;
}
public IStatus perform(IPublisherInfo publisherinfo, IPublisherResult result, IProgressMonitor monitor) {
setPublisherInfo(publisherinfo);
ExecutablesDescriptor brandedExecutables = brandExecutables(executables);
try {
publishExecutableIU(brandedExecutables, result);
publishExecutableCU(brandedExecutables, result);
publishExecutableSetter(brandedExecutables, result);
} finally {
if (brandedExecutables.isTemporary())
FileUtils.deleteAll(brandedExecutables.getLocation());
}
return Status.OK_STATUS;
}
/**
* Publishes the IUs that cause the executable to be actually set as the launcher for
* the profile
*/
private void publishExecutableSetter(ExecutablesDescriptor brandedExecutables, IPublisherResult result) {
InstallableUnitDescription iud = new MetadataFactory.InstallableUnitDescription();
String executableName = brandedExecutables.getExecutableName();
String id = getExecutableId() + '.' + executableName;
iud.setId(id);
iud.setVersion(version);
iud.setTouchpointType(PublisherHelper.TOUCHPOINT_OSGI);
iud.setCapabilities(new IProvidedCapability[] {createSelfCapability(id, version)});
String filter = createFilterSpec(configSpec);
if (filter.length() > 0)
iud.setFilter(filter);
Map touchpointData = new HashMap();
touchpointData.put("configure", "setLauncherName(name:" + executableName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
touchpointData.put("unconfigure", "setLauncherName()"); //$NON-NLS-1$ //$NON-NLS-2$
iud.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData));
result.addIU(MetadataFactory.createInstallableUnit(iud), IPublisherResult.ROOT);
}
/**
* Publishes IUs and CUs for the files that make up the launcher for a given
* ws/os/arch combination.
*/
protected void publishExecutableIU(ExecutablesDescriptor execDescriptor, IPublisherResult result) {
// Create the IU for the executable
InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription();
String id = getExecutableId();
iu.setId(id);
iu.setVersion(version);
String filter = createFilterSpec(configSpec);
iu.setFilter(filter);
iu.setSingleton(true);
iu.setTouchpointType(PublisherHelper.TOUCHPOINT_NATIVE);
String namespace = ConfigCUsAction.getAbstractCUCapabilityNamespace(idBase, TYPE, flavor, configSpec);
String capabilityId = ConfigCUsAction.getAbstractCUCapabilityId(idBase, TYPE, flavor, configSpec);
IProvidedCapability executableCapability = MetadataFactory.createProvidedCapability(namespace, capabilityId, version);
IProvidedCapability selfCapability = createSelfCapability(id, version);
iu.setCapabilities(new IProvidedCapability[] {selfCapability, executableCapability});
//Create the artifact descriptor. we have several files so no path on disk
IArtifactKey key = PublisherHelper.createBinaryArtifactKey(id, version);
iu.setArtifacts(new IArtifactKey[] {key});
IArtifactDescriptor descriptor = PublisherHelper.createArtifactDescriptor(info.getArtifactRepository(), key, null);
publishArtifact(descriptor, execDescriptor.getFiles(), null, info, createRootPrefixComputer(execDescriptor.getLocation()));
if (execDescriptor.isTemporary())
FileUtils.deleteAll(execDescriptor.getLocation());
// setup a requirement between the executable and the launcher fragment that has the shared library
String[] config = parseConfigSpec(configSpec);
String ws = config[0];
String os = config[1];
String arch = config[2];
String launcherFragment = EquinoxLauncherCUAction.ORG_ECLIPSE_EQUINOX_LAUNCHER + '.' + ws + '.' + os;
if (!(Constants.OS_MACOSX.equals(os) && !Constants.ARCH_X86_64.equals(arch)))
launcherFragment += '.' + arch;
iu.setRequiredCapabilities(new IRequiredCapability[] {MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, launcherFragment, VersionRange.emptyRange, filter, false, false)});
result.addIU(MetadataFactory.createInstallableUnit(iu), IPublisherResult.ROOT);
}
private String getExecutableId() {
return createCUIdString(idBase, TYPE, "", configSpec); //$NON-NLS-1$
}
// Create the CU that installs (e.g., unzips) the executable
private void publishExecutableCU(ExecutablesDescriptor execDescriptor, IPublisherResult result) {
InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription();
String id = createCUIdString(idBase, TYPE, flavor, configSpec);
cu.setId(id);
cu.setVersion(version);
cu.setFilter(createFilterSpec(configSpec));
String executableId = getExecutableId();
cu.setHost(new IRequiredCapability[] {MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, executableId, new VersionRange(version, true, version, true), null, false, false)});
cu.setProperty(InstallableUnitDescription.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString());
//TODO bug 218890, would like the fragment to provide the launcher capability as well, but can't right now.
cu.setCapabilities(new IProvidedCapability[] {PublisherHelper.createSelfCapability(id, version)});
cu.setTouchpointType(PublisherHelper.TOUCHPOINT_NATIVE);
String[] config = parseConfigSpec(configSpec);
String os = config[1];
Map touchpointData = computeInstallActions(execDescriptor, os);
cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData));
IInstallableUnit unit = MetadataFactory.createInstallableUnit(cu);
result.addIU(unit, IPublisherResult.ROOT);
}
private Map computeInstallActions(ExecutablesDescriptor execDescriptor, String os) {
Map touchpointData = new HashMap();
String configurationData = "unzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$
if (Constants.OS_MACOSX.equals(os)) {
String execName = execDescriptor.getExecutableName();
configurationData += " chmod(targetDir:${installFolder}/" + execName + ".app/Contents/MacOS/, targetFile:" + execName + ", permissions:755);"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} else if (!Constants.OS_WIN32.equals(os)) {
// We are on linux/unix. by default set all of the files to be executable.
File[] fileList = execDescriptor.getFiles();
for (int i = 0; i < fileList.length; i++)
configurationData += " chmod(targetDir:${installFolder}, targetFile:" + fileList[i].getName() + ", permissions:755);"; //$NON-NLS-1$ //$NON-NLS-2$
}
touchpointData.put("install", configurationData); //$NON-NLS-1$
String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$
touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$
return touchpointData;
}
/**
* Brands a copy of the given executable descriptor with the information in the
* current product definition. The files described in the descriptor are also copied
* to a temporary location to avoid destructive modification.
*
* @param descriptor the executable descriptor to brand.
* @return the new descriptor
*/
protected ExecutablesDescriptor brandExecutables(ExecutablesDescriptor descriptor) {
ExecutablesDescriptor result = new ExecutablesDescriptor(descriptor);
result.makeTemporaryCopy();
IBrandingAdvice advice = getBrandingAdvice();
if (advice == null)
partialBrandExecutables(result);
else
fullBrandExecutables(result, advice);
return result;
}
private IBrandingAdvice getBrandingAdvice() {
// there is expected to only be one branding advice for a given configspec so
// just return the first one we find.
Collection advice = info.getAdvice(configSpec, true, null, null, IBrandingAdvice.class);
for (Iterator i = advice.iterator(); i.hasNext();)
return (IBrandingAdvice) i.next();
return null;
}
protected void fullBrandExecutables(ExecutablesDescriptor descriptor, IBrandingAdvice advice) {
BrandingIron iron = new BrandingIron();
iron.setIcons(advice.getIcons());
String name = advice.getExecutableName();
if (name == null)
name = "eclipse"; //$NON-NLS-1$
iron.setName(name);
iron.setOS(advice.getOS());
iron.setRoot(descriptor.getLocation().getAbsolutePath());
try {
iron.brand();
descriptor.setExecutableName(name, true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void partialBrandExecutables(ExecutablesDescriptor descriptor) {
File[] list = descriptor.getFiles();
for (int i = 0; i < list.length; i++)
mungeExecutableFileName(list[i], descriptor);
descriptor.setExecutableName("eclipse", true); //$NON-NLS-1$
}
// TODO This method is a temporary hack to rename the launcher.exe files
// to eclipse.exe (or "launcher" to "eclipse"). Eventually we will either hand-craft
// metadata/artifacts for launchers, or alter the delta pack to contain eclipse-branded
// launchers.
private void mungeExecutableFileName(File file, ExecutablesDescriptor descriptor) {
if (file.getName().equals("launcher")) { //$NON-NLS-1$
File newFile = new File(file.getParentFile(), "eclipse"); //$NON-NLS-1$
file.renameTo(newFile);
descriptor.replace(file, newFile);
} else if (file.getName().equals("launcher.exe")) { //$NON-NLS-1$
File newFile = new File(file.getParentFile(), "eclipse.exe"); //$NON-NLS-1$
file.renameTo(newFile);
descriptor.replace(file, newFile);
}
}
}