blob: 91f1a093296aae5566b00bd4356a5efdf99d8598 [file] [log] [blame]
package org.eclipse.equinox.internal.p2.publisher.actions;
import java.io.*;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.FileUtils;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
import org.eclipse.equinox.internal.p2.publisher.AbstractPublishingAction;
import org.eclipse.equinox.internal.p2.publisher.Activator;
import org.eclipse.osgi.service.environment.Constants;
public class ExecutablesDescriptor {
private File location;
private Set files;
private String executableName;
private boolean temporary = false;
private String os;
public static File findExecutable(String os, File root, String baseName) {
// TODO this may need to get more intelligent
// if MacOS its going to be baseName.app/Contents/MacOS/baseName
if (Constants.OS_MACOSX.equals(os)) {
return new File(root, baseName + ".app/Contents/MacOS/" + baseName);
}
// if it is not Mac and not Windows it must be a UNIX flavor
if (!Constants.OS_WIN32.equals(os)) {
return new File(root, baseName);
}
// otherwise we are left with windows
return new File(root, baseName + ".exe");
}
/**
* Return the root directory of the executables folder for the given configSpec. The folder
* is expected to be part of the standard Eclipse executables feature whose structure is
* embedded here.
* @param executablesFeatureLocation the location of the executables feature
* @param configSpec the configuration to lookup
* @return the root location of the requested executables
*/
public static ExecutablesDescriptor createExecutablesFromFeature(File executablesFeatureLocation, String configSpec) {
// TODO consider handling JAR'd features here...
if (executablesFeatureLocation == null || !executablesFeatureLocation.exists())
return null;
String[] config = AbstractPublishingAction.parseConfigSpec(configSpec);
File result = new File(executablesFeatureLocation, "bin/" + config[0] + "/" + config[1] + "/" + config[2]);
if (!result.exists())
return null;
return new ExecutablesDescriptor(config[1], "launcher", result, new File[] {result});
}
/**
* Create an executable descriptor based on the given location, os and name.
* This method is typically used to identify the executable related files in existing
* unmanaged configurations.
* @param os
* @param location
* @param executable
* @return the created descriptor
*/
public static ExecutablesDescriptor createDescriptor(String os, String executable, File location) {
if (Constants.OS_MACOSX.equals(os))
return createMacDescriptor(os, executable, location);
// if it is not Mac and not Windows it must be a UNIX flavor
if (!Constants.OS_WIN32.equals(os))
return createUnixDescriptor(os, executable, location);
// Nothing else so it must be Windows
return createWindowsDescriptor(os, executable, location);
}
private static ExecutablesDescriptor createWindowsDescriptor(String os, String executable, File location) {
ExecutablesDescriptor result = new ExecutablesDescriptor(os, executable, location, null);
File file = new File(location, executable + ".exe"); //$NON-NLS-1$
if (file.isFile())
result.addFile(file);
file = new File(location, "eclipsec.exe"); //$NON-NLS-1$
if (file.isFile())
result.addFile(file);
return result;
}
private static ExecutablesDescriptor createUnixDescriptor(String os, String executable, File location) {
ExecutablesDescriptor result = new ExecutablesDescriptor(os, executable, location, null);
File[] files = location.listFiles();
for (int i = 0; files != null && i < files.length; i++) {
String extension = new Path(files[i].getName()).getFileExtension();
if (files[i].isFile() && (extension == null || extension.equals("so"))) //$NON-NLS-1$
result.addFile(files[i]);
}
return result;
}
private static ExecutablesDescriptor createMacDescriptor(String os, String executable, File location) {
File files[] = location.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.substring(name.length() - 4, name.length()).equalsIgnoreCase(".app"); //$NON-NLS-1$
}
});
return new ExecutablesDescriptor(os, executable, location, files);
}
public ExecutablesDescriptor(String os, String executable, File location, File[] files) {
this.os = os;
this.executableName = executable;
this.location = location;
if (files == null)
this.files = new HashSet(11);
else {
this.files = new HashSet(files.length);
for (int i = 0; i < files.length; i++)
addAllFiles(files[i]);
}
}
public ExecutablesDescriptor(ExecutablesDescriptor descriptor) {
this.os = descriptor.os;
this.location = descriptor.location;
this.executableName = descriptor.executableName;
this.temporary = descriptor.temporary;
this.files = new HashSet(descriptor.files);
}
public void addAllFiles(File file) {
if (file.isFile())
files.add(relativize(file));
else {
File absolute = file.isAbsolute() ? file : new File(location, file.getPath());
File[] list = absolute.listFiles();
for (int i = 0; i < list.length; i++)
addAllFiles(list[i]);
}
}
public void addFile(File file) {
files.add(relativize(file));
}
// do a simple relativization by removing all the bits before the location
private File relativize(File file) {
if (!file.isAbsolute())
return file;
String path = file.getPath();
if (!path.startsWith(location.getPath()))
throw new IllegalArgumentException(file.toString() + " must be related to " + location); //$NON-NLS-1$
path = path.substring(location.getPath().length());
// trim off any separator. This accomodates people who set the location with a trailing /
if (path.startsWith("/") || path.startsWith("\\")) //$NON-NLS-1$//$NON-NLS-2$
path = path.substring(1);
return new File(path);
}
public void removeFile(File file) {
files.remove(relativize(file));
}
public void replace(File oldFile, File newFile) {
removeFile(oldFile);
addFile(newFile);
}
public File[] getFiles() {
File[] result = (File[]) files.toArray(new File[files.size()]);
for (int i = 0; i < result.length; i++)
result[i] = new File(location, result[i].getPath());
return result;
}
public String getExecutableName() {
return executableName;
}
public File getExecutable() {
return findExecutable(os, location, executableName);
}
public File getLocation() {
return location;
}
public void setLocation(File value) {
location = value;
}
public boolean isTemporary() {
return temporary;
}
public void setExecutableName(String value, boolean updateFiles) {
if (updateFiles)
updateExecutableName(value);
executableName = value;
}
public void makeTemporaryCopy() {
if (isTemporary())
return;
File tempFile = null;
try {
tempFile = File.createTempFile("p2.brandingIron", ""); //$NON-NLS-1$ //$NON-NLS-2$
tempFile.delete();
for (Iterator i = files.iterator(); i.hasNext();)
FileUtils.copy(location, tempFile, (File) i.next(), true);
} catch (IOException e) {
LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Error publishing artifacts", e)); //$NON-NLS-1$
}
location = tempFile;
temporary = true;
}
/**
* If the executable represented by this descriptor has been branded then a mess
* of files have been renamed. Here scan the descriptor's file list and update the names
* taking into accoun the different layout on different OSes.
* @param newName the new name of the executable.
*/
private void updateExecutableName(String newName) {
if (newName.equalsIgnoreCase(executableName))
return;
String targetIni = executableName + ".ini"; //$NON-NLS-1$
String targetExecutable = executableName;
String executableExtension = Constants.OS_WIN32.equals(os) ? ".exe" : ""; //$NON-NLS-1$ //$NON-NLS-2$
targetExecutable = executableName + executableExtension;
for (Iterator i = files.iterator(); i.hasNext();) {
File file = (File) i.next();
String base = file.getParent();
// use String concatenation here because new File("", "foo") is absolute on at least windows...
base = base == null ? "" : base + "/"; //$NON-NLS-1$ //$NON-NLS-2$
if (Constants.OS_MACOSX.equals(os) && base.startsWith(executableName + ".app")) //$NON-NLS-1$
base = newName + ".app" + base.substring(executableName.length() + 4); //$NON-NLS-1$
if (file.getName().equalsIgnoreCase(targetExecutable))
replace(file, new File(base + newName + executableExtension));
else if (file.getName().equalsIgnoreCase(targetIni))
replace(file, new File(base + newName + ".ini")); //$NON-NLS-1$
else if (Constants.OS_MACOSX.equals(os))
replace(file, new File(base + file.getName()));
}
}
}