diff options
author | Jeff McAffer | 2008-03-14 04:24:12 +0000 |
---|---|---|
committer | Jeff McAffer | 2008-03-14 04:24:12 +0000 |
commit | 618de1745b89297893c6c48e8bd36972a1a92d87 (patch) | |
tree | 967fc61dedf8dc293f8619810f0051b956609b17 /bundles/org.eclipse.equinox.p2.publisher/src | |
parent | 4acb3c0f22fd044b4c91500ffd68036a51f06649 (diff) | |
download | rt.equinox.p2-618de1745b89297893c6c48e8bd36972a1a92d87.tar.gz rt.equinox.p2-618de1745b89297893c6c48e8bd36972a1a92d87.tar.xz rt.equinox.p2-618de1745b89297893c6c48e8bd36972a1a92d87.zip |
Cut the chord from metadatagenerator
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.publisher/src')
44 files changed, 6374 insertions, 280 deletions
diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractGeneratorApplication.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractPublisherApplication.java index 96a005a08..20b3b2370 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractGeneratorApplication.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractPublisherApplication.java @@ -30,7 +30,7 @@ import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadata import org.eclipse.osgi.util.NLS; import org.osgi.framework.ServiceRegistration; -public abstract class AbstractGeneratorApplication implements IApplication { +public abstract class AbstractPublisherApplication implements IApplication { // The mapping rules for in-place generation need to construct paths into the structure // of an eclipse installation; in the future the default artifact mapping declared in @@ -62,6 +62,8 @@ public abstract class AbstractGeneratorApplication implements IApplication { protected boolean reusePackedFiles = false; protected void initialize(PublisherInfo info) throws ProvisionException { + if (inplace) + initializeForInplace(info); initializeRepositories(info); } @@ -113,8 +115,8 @@ public abstract class AbstractGeneratorApplication implements IApplication { } catch (MalformedURLException e) { // ought not happen... } - info.setPublishArtifactRepository(true); - info.setPublishArtifacts(false); + info.setArtifactOptions(info.getArtifactOptions() | IPublisherInfo.A_INDEX); + info.setArtifactOptions(info.getArtifactOptions() | IPublisherInfo.A_PUBLISH); } protected void initializeMetadataRepository(PublisherInfo info) throws ProvisionException { @@ -192,10 +194,13 @@ public abstract class AbstractGeneratorApplication implements IApplication { protected void processFlag(String arg, PublisherInfo info) { if (arg.equalsIgnoreCase("-publishArtifacts") || arg.equalsIgnoreCase("-pa")) //$NON-NLS-1$ //$NON-NLS-2$ - info.setPublishArtifacts(true); + info.setArtifactOptions(info.getArtifactOptions() | IPublisherInfo.A_PUBLISH); if (arg.equalsIgnoreCase("-publishArtifactRepository") || arg.equalsIgnoreCase("-par")) //$NON-NLS-1$ //$NON-NLS-2$ - info.setPublishArtifactRepository(true); + info.setArtifactOptions(info.getArtifactOptions() | IPublisherInfo.A_INDEX); + + if (arg.equalsIgnoreCase("-overwriteArtifacts")) //$NON-NLS-1$ + info.setArtifactOptions(info.getArtifactOptions() | IPublisherInfo.A_OVERWRITE); if (arg.equalsIgnoreCase("-append")) //$NON-NLS-1$ append = true; diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractPublishingAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractPublishingAction.java new file mode 100644 index 000000000..fc0729bc0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/AbstractPublishingAction.java @@ -0,0 +1,158 @@ +package org.eclipse.equinox.internal.p2.publisher; + +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.provisional.p2.artifact.repository.IArtifactDescriptor; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepository; +import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException; + +public abstract class AbstractPublishingAction implements IPublishingAction { + + public static final int AS_IS = 1; + public static final int INCLUDE_ROOT = 2; + + public static final String CONFIG_SEGMENT_SEPARATOR = "."; //$NON-NLS-1$ + + /** + * 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()]); + } + + /** + * Returns a string array of { ws, os, arch } as parsed from the given string + * @param configSpec the string to parse + * @return the ws, os, arch form of the given string + */ + public static String[] parseConfigSpec(String configSpec) { + String[] result = getArrayFromString(configSpec, CONFIG_SEGMENT_SEPARATOR); + return result; + } + + /** + * Returns the LDAP filter form that matches the given config spec. Returns + * an empty String if the spec does not identify an ws, os or arch. + * @param configSpec a config spec to filter + * @return the LDAP filter for the given spec. + */ + public static String createFilterSpec(String configSpec) { + String[] config = parseConfigSpec(configSpec); + if (config[0] != null || config[1] != null || config[2] != null) { + String filterWs = config[0] != null ? "(osgi.ws=" + config[0] + ")" : ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + String filterOs = config[1] != null ? "(osgi.os=" + config[1] + ")" : ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + String filterArch = config[2] != null ? "(osgi.arch=" + config[2] + ")" : ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return "(& " + filterWs + filterOs + filterArch + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + return ""; //$NON-NLS-1$ + } + + /** + * Returns the normalized string form of the given config spec. This is useful for putting + * in IU ids etc. Note that the result is not intended to be machine readable (i.e., parseConfigSpec + * may not work on the result). + * @param configSpec the config spec to format + * @return the readable format of the given config spec + */ + public static String createIdString(String configSpec) { + String[] config = parseConfigSpec(configSpec); + return config[0] + '.' + config[1] + '.' + config[2]; + } + + /** + * Returns the canonical form of config spec with the given ws, os and arch. + * Note that the result is intended to be machine readable (i.e., parseConfigSpec + * will parse the the result). + * @param ws the window system + * @param os the operating system + * @param arch the machine architecture + * @return the machine readable format of the given config spec + */ + public static String createConfigSpec(String ws, String os, String arch) { + return ws + '.' + os + '.' + arch; + } + + protected void publishArtifact(IArtifactDescriptor descriptor, File base, File[] files, IPublisherInfo info, int mode) { + IArtifactRepository destination = info.getArtifactRepository(); + + if (descriptor == null || destination == null) + return; + + // publish the given files + publishArtifact(descriptor, files, info, mode); + + // if we are assimilating pack200 files then add the packed descriptor + // into the repo assuming it does not already exist. + boolean reuse = "true".equals(destination.getProperties().get(AbstractPublisherApplication.PUBLISH_PACK_FILES_AS_SIBLINGS)); //$NON-NLS-1$ + if (base != null && reuse && (info.getArtifactOptions() & IPublisherInfo.A_PUBLISH) > 0) { + File packFile = new Path(base.getAbsolutePath()).addFileExtension("pack.gz").toFile(); //$NON-NLS-1$ + if (packFile.exists()) { + IArtifactDescriptor ad200 = MetadataGeneratorHelper.createPack200ArtifactDescriptor(descriptor.getArtifactKey(), packFile, descriptor.getProperty(IArtifactDescriptor.ARTIFACT_SIZE)); + publishArtifact(ad200, new File[] {packFile}, info, AS_IS | INCLUDE_ROOT); + } + } + } + + protected void publishArtifact(IArtifactDescriptor descriptor, File[] files, IPublisherInfo info, int mode) { + IArtifactRepository destination = info.getArtifactRepository(); + + // if the destination already contains the descriptor, there is nothing to do. + if (destination.contains(descriptor)) + return; + // if all we are doing is indexing things then add the descriptor and get on with ti + if ((info.getArtifactOptions() & IPublisherInfo.A_PUBLISH) == 0) { + destination.addDescriptor(descriptor); + return; + } + + boolean overwrite = (info.getArtifactOptions() & IPublisherInfo.A_OVERWRITE) > 0; + // if there is just one file and the mode is as-is, just copy the file into the repo + if (((mode & AS_IS) > 0) && files.length == 1) { + try { + OutputStream output = destination.getOutputStream(descriptor, overwrite); + if (output == null) + return; + output = new BufferedOutputStream(output); + FileUtils.copyStream(new BufferedInputStream(new FileInputStream(files[0])), true, output, true); + } catch (ProvisionException e) { + LogHelper.log(e.getStatus()); + } catch (IOException e) { + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Error publishing artifacts", e)); //$NON-NLS-1$ + } + } else { + // otherwise, zip up the files and copy the zip into the repo + File tempFile = null; + try { + OutputStream output = destination.getOutputStream(descriptor, overwrite); + if (output == null) + return; + output = new BufferedOutputStream(output); + tempFile = File.createTempFile("p2.generator", ""); //$NON-NLS-1$ //$NON-NLS-2$ + FileUtils.zip(files, tempFile, (mode & INCLUDE_ROOT) > 0); + if (output != null) + FileUtils.copyStream(new BufferedInputStream(new FileInputStream(tempFile)), true, output, true); + } catch (ProvisionException e) { + LogHelper.log(e.getStatus()); + } catch (IOException e) { + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Error publishing artifacts", e)); //$NON-NLS-1$ + } finally { + if (tempFile != null) + tempFile.delete(); + } + } + } + + public abstract IStatus perform(IPublisherInfo info, IPublisherResult results); +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/BundleDescriptionFactory.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/BundleDescriptionFactory.java new file mode 100644 index 000000000..776e78252 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/BundleDescriptionFactory.java @@ -0,0 +1,355 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; +import org.eclipse.equinox.internal.p2.metadata.repository.Activator; +import org.eclipse.osgi.service.pluginconversion.PluginConversionException; +import org.eclipse.osgi.service.pluginconversion.PluginConverter; +import org.eclipse.osgi.service.resolver.*; +import org.eclipse.osgi.util.ManifestElement; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.BundleException; + +public class BundleDescriptionFactory { + public static final String DIR = "dir"; //$NON-NLS-1$ + public static final String JAR = "jar"; //$NON-NLS-1$ + private static final String FEATURE_FILENAME_DESCRIPTOR = "feature.xml"; //$NON-NLS-1$ + private static final String PLUGIN_FILENAME_DESCRIPTOR = "plugin.xml"; //$NON-NLS-1$ + private static final String FRAGMENT_FILENAME_DESCRIPTOR = "fragment.xml"; //$NON-NLS-1$ + + public static String BUNDLE_SHAPE = "Eclipse-BundleShape"; //$NON-NLS-1$ + + // static final String DEFAULT_BUNDLE_LOCALIZATION = "plugin"; //$NON-NLS-1$ + // static final String PROPERTIES_FILE_EXTENSION = ".properties"; //$NON-NLS-1$ + // static final String MANIFEST_LOCALIZATIONS = "eclipse.p2.manifest.localizations"; //$NON-NLS-1$ + // + // static final Locale DEFAULT_LOCALE = new Locale("df", "LT"); //$NON-NLS-1$//$NON-NLS-2$ + // static final Locale PSEUDO_LOCALE = new Locale("zz", "ZZ"); //$NON-NLS-1$//$NON-NLS-2$ + + StateObjectFactory factory; + State state; + + public BundleDescriptionFactory(StateObjectFactory factory, State state) { + this.factory = factory; + this.state = state; + //TODO find a state and a factory when not provided + } + + private static PluginConverter acquirePluginConverter() { + return (PluginConverter) ServiceHelper.getService(Activator.getContext(), PluginConverter.class.getName()); + } + + private static Dictionary convertPluginManifest(File bundleLocation, boolean logConversionException) { + PluginConverter converter; + try { + converter = acquirePluginConverter(); + if (converter == null) + return null; + return converter.convertManifest(bundleLocation, false, null, true, null); + } catch (PluginConversionException convertException) { + if (bundleLocation.getName().equals(FEATURE_FILENAME_DESCRIPTOR)) + return null; + if (!new File(bundleLocation, PLUGIN_FILENAME_DESCRIPTOR).exists() && !new File(bundleLocation, FRAGMENT_FILENAME_DESCRIPTOR).exists()) + return null; + if (logConversionException) { + IStatus status = new Status(IStatus.WARNING, Activator.ID, 0, NLS.bind(Messages.exception_errorConverting, bundleLocation.getAbsolutePath()), convertException); + System.out.println(status); + //TODO Need to find a way to get a logging service to log + } + return null; + } + } + + public BundleDescription getBundleDescription(Dictionary enhancedManifest, File bundleLocation) { + try { + BundleDescription descriptor = factory.createBundleDescription(state, enhancedManifest, bundleLocation != null ? bundleLocation.getAbsolutePath() : null, 1); //TODO Do we need to have a real bundle id + descriptor.setUserObject(enhancedManifest); + return descriptor; + } catch (BundleException e) { + // IStatus status = new Status(IStatus.WARNING, IPDEBuildConstants.PI_PDEBUILD, EXCEPTION_STATE_PROBLEM, NLS.bind(Messages.exception_stateAddition, enhancedManifest.get(Constants.BUNDLE_NAME)), e); + // BundleHelper.getDefault().getLog().log(status); + System.err.println(NLS.bind(Messages.exception_stateAddition, bundleLocation != null ? bundleLocation.getAbsoluteFile() : null)); + return null; + } + } + + public BundleDescription getBundleDescription(File bundleLocation) { + Dictionary manifest = loadManifest(bundleLocation); + if (manifest == null) + return null; + return getBundleDescription(manifest, bundleLocation); + } + + public BundleDescription getBundleDescription(InputStream manifestStream, File bundleLocation) { + Hashtable entries = new Hashtable(); + try { + ManifestElement.parseBundleManifest(manifestStream, entries); + return getBundleDescription(entries, bundleLocation); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (BundleException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + public static Dictionary loadManifest(File bundleLocation) { + InputStream manifestStream = null; + ZipFile jarFile = null; + try { + if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && bundleLocation.isFile()) { //$NON-NLS-1$ + jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); + ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME); + if (manifestEntry != null) { + manifestStream = jarFile.getInputStream(manifestEntry); + } + } else { + manifestStream = new BufferedInputStream(new FileInputStream(new File(bundleLocation, JarFile.MANIFEST_NAME))); + } + } catch (IOException e) { + //ignore + } + + Dictionary manifest = null; + if (manifestStream != null) { + try { + manifest = manifestToProperties(new Manifest(manifestStream).getMainAttributes()); + } catch (IOException ioe) { + return null; + } finally { + try { + manifestStream.close(); + } catch (IOException e1) { + //Ignore + } + try { + if (jarFile != null) + jarFile.close(); + } catch (IOException e2) { + //Ignore + } + } + } else { + manifest = convertPluginManifest(bundleLocation, true); + } + + if (manifest == null) + return null; + + //Deal with the pre-3.0 plug-in shape who have a default jar manifest.mf + if (manifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME) == null) + manifest = convertPluginManifest(bundleLocation, true); + + // if the bundle itself does not define its shape, infer the shape from the current form + if (manifest.get(BUNDLE_SHAPE) == null) + manifest.put(BUNDLE_SHAPE, bundleLocation.isDirectory() ? DIR : JAR); + getManifestLocalizations(manifest, bundleLocation); + // localizeManifest(manifest, bundleLocation); + return manifest; + } + + // private Properties loadProperties(File bundleLocation, String localizationFile) throws IOException { + // Properties result = new Properties(); + // InputStream propertyStream = null; + // try { + // try { + // if (bundleLocation.isDirectory()) + // propertyStream = new FileInputStream(new File(bundleLocation, localizationFile)); + // else { + // URLConnection connection = new URL("jar:" + bundleLocation.toURL().toExternalForm() + "!/" + localizationFile).openConnection(); //$NON-NLS-1$ //$NON-NLS-2$ + // connection.setUseCaches(false); + // propertyStream = connection.getInputStream(); + // } + // } catch (FileNotFoundException e) { + // // if there is no messages file then just return; + // return result; + // } + // result.load(propertyStream); + // } finally { + // if (propertyStream != null) + // propertyStream.close(); + // } + // return result; + // } + + // Collect the manifest localizations from the bundle directory + // and store them in the manifest. + private static void getManifestLocalizations(Dictionary manifest, File bundleLocation) { + // Map localizations; + // Locale defaultLocale = null; // = Locale.ENGLISH; // TODO: get this from GeneratorInfo + // String bundleLocalization = (String) manifest.get(Constants.BUNDLE_LOCALIZATION); + // if (bundleLocalization == null || bundleLocalization.trim().length() == 0) + // bundleLocalization = DEFAULT_BUNDLE_LOCALIZATION; + // + // if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && //$NON-NLS-1$ + // bundleLocation.isFile()) { + // localizations = getJarManifestLocalization(bundleLocation, bundleLocalization, manifest, defaultLocale); + // } else { + // localizations = getDirManifestLocalization(bundleLocation, bundleLocalization, manifest, defaultLocale); + // } + // + // if (localizations.size() > 0) { + // manifest.put(MANIFEST_LOCALIZATIONS, localizations); + // } + } + + // private Map getJarManifestLocalization(File bundleLocation, String bundleLocalization, Dictionary manifest, Locale defaultLocale) { + // ZipFile jarFile = null; + // Map localizations = new HashMap(4); + // try { + // jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); + // for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { + // ZipEntry nextEntry = (ZipEntry) entries.nextElement(); + // String nextName = nextEntry.getName(); + // String localeString = getLocaleString(nextName, bundleLocalization); + // + // if (!nextEntry.isDirectory() && localeString != null) { + // Locale nextLocale = getLocale(localeString); + // InputStream stream = null; + // try { + // stream = jarFile.getInputStream(nextEntry); + // Properties properties = new Properties(); + // properties.load(stream); + // Properties localizedStrings = getLocalizedProperties(manifest, properties); + // if (localizedStrings.size() > 0) { + // localizations.put(nextLocale, localizedStrings); + // if (DEFAULT_LOCALE.equals(nextLocale) && defaultLocale != null) { + // localizations.put(nextLocale, localizedStrings); + // } + // } + // } finally { + // if (stream != null) + // stream.close(); + // } + // } + // } + // } catch (IOException ioe) { + // ioe.printStackTrace(); + // } finally { + // if (jarFile != null) { + // try { + // jarFile.close(); + // } catch (IOException ioe) { + // // do nothing + // } + // } + // } + // + // return localizations; + // } + // + // private Map getDirManifestLocalization(File bundleLocation, String bundleLocalization, Dictionary manifest, Locale defaultLocale) { + // File localizationPath = new File(bundleLocation, bundleLocalization); + // File localizationDir = localizationPath.getParentFile(); + // String localizationFile = localizationPath.getName(); + // String[] localizationFiles = localizationDir.list(new LocalizationFileFilter(localizationFile)); + // + // HashMap localizations = null; + // + // if (localizationFiles != null) { + // localizations = new HashMap(localizationFiles.length); + // for (int i = 0; i < localizationFiles.length; i++) { + // String nextFile = localizationFiles[i]; + // Locale nextLocale = getLocale(getLocaleString(nextFile, localizationFile)); + // + // try { + // Properties properties = loadProperties(bundleLocation, nextFile); + // Properties localizedStrings = getLocalizedProperties(manifest, properties); + // if (localizedStrings.size() > 0) { + // localizations.put(nextLocale, localizedStrings); + // if (DEFAULT_LOCALE.equals(nextLocale) && defaultLocale != null) { + // localizations.put(nextLocale, localizedStrings); + // } + // } + // } catch (IOException ioe) { + // ioe.printStackTrace(); + // } + // } + // } + // + // return localizations; + // } + + // private class LocalizationFileFilter implements FilenameFilter { + // + // String filenamePrefix; + // + // public LocalizationFileFilter(String filenamePrefix) { + // this.filenamePrefix = filenamePrefix; + // } + // + // /* (non-Javadoc) + // * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) + // */ + // public boolean accept(File directory, String filename) { + // return (getLocaleString(filename, filenamePrefix) != null ? true : false); + // } + // } + + // static public String getLocaleString(String filename, String filenamePrefix) { + // String localeString = null; + // if (filename.startsWith(filenamePrefix) && filename.endsWith(PROPERTIES_FILE_EXTENSION)) { + // if (filename.length() > filenamePrefix.length() + PROPERTIES_FILE_EXTENSION.length()) { + // localeString = filename.substring(filenamePrefix.length() + 1, filename.length() - PROPERTIES_FILE_EXTENSION.length()); + // } else { + // localeString = ""; //$NON-NLS-1$ + // } + // } + // return localeString; + // } + + // static private Locale getLocale(String localeString) { + // Locale locale = DEFAULT_LOCALE; + // if (localeString.length() == 5 && localeString.indexOf('_') == 2) { + // locale = new Locale(localeString.substring(0, 2), localeString.substring(3, 5)); + // } else if (localeString.length() == 2) { + // locale = new Locale(localeString.substring(0, 2)); + // } + // return locale; + // } + // + // static private Properties getLocalizedProperties(Dictionary manifest, Properties properties) { + // // Walk over the manifest and find all %xxx with the string value + // // in the properties file and copy them to the localized properties. + // Properties localizedProperties = new Properties(); + // for (Enumeration e = manifest.keys(); e.hasMoreElements();) { + // String key = (String) e.nextElement(); + // Object value = manifest.get(key); + // if (value instanceof String) { + // String stringValue = (String) value; + // if (stringValue.startsWith("%")) { //$NON-NLS-1$ + // String newValue = properties.getProperty(stringValue.substring(1)); + // if (newValue != null) + // localizedProperties.put(key, newValue); + // } + // } + // } + // return localizedProperties; + // } + + private static Properties manifestToProperties(Attributes attributes) { + Properties result = new Properties(); + for (Iterator i = attributes.keySet().iterator(); i.hasNext();) { + Attributes.Name key = (Attributes.Name) i.next(); + result.put(key.toString(), attributes.get(key)); + } + return result; + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/FileSetDescriptor.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/FileSetDescriptor.java new file mode 100644 index 000000000..91a204695 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/FileSetDescriptor.java @@ -0,0 +1,50 @@ +package org.eclipse.equinox.internal.p2.publisher; + +import java.util.ArrayList; + +public class FileSetDescriptor { + private final String key; + private String configSpec = null; + private String files = ""; //$NON-NLS-1$ + private final ArrayList permissions = new ArrayList(); + private String links = ""; //$NON-NLS-1$ + + public FileSetDescriptor(String key, String configSpec) { + this.key = key; + this.configSpec = configSpec; + } + + public void setFiles(String property) { + files = property; + } + + // a permission spec is { <perm>, file patterns } + public void addPermissions(String[] property) { + permissions.add(property); + } + + public void setLinks(String property) { + links = property; + } + + public String getConfigSpec() { + return configSpec; + } + + public String getKey() { + return key; + } + + public String getLinks() { + return links; + } + + public String[][] getPermissions() { + return (String[][]) permissions.toArray(new String[permissions.size()][]); + } + + public String getFiles() { + return files; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/GeneratorBundleInfo.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/GeneratorBundleInfo.java new file mode 100644 index 000000000..c2cf5b542 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/GeneratorBundleInfo.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2006, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher; + +import java.io.ByteArrayInputStream; +import org.eclipse.equinox.internal.p2.core.helpers.Headers; +import org.eclipse.equinox.internal.provisional.frameworkadmin.BundleInfo; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; + +public class GeneratorBundleInfo extends BundleInfo { + // public static final int NO_LEVEL = -1; + + // private String symbolicName; + // private String version; + // private String location; + // private int expectedState; + // private int startLevel = NO_LEVEL; + // private String manifest; + + private String specialConfigCommands; + private String specialUnconfigCommands; + + public GeneratorBundleInfo(BundleInfo bInfo) { + super.setBundleId(bInfo.getBundleId()); + super.setLocation(bInfo.getLocation()); + super.setManifest(bInfo.getManifest()); + super.setMarkedAsStarted(bInfo.isMarkedAsStarted()); + super.setResolved(bInfo.isResolved()); + super.setStartLevel(bInfo.getStartLevel()); + super.setSymbolicName(bInfo.getSymbolicName()); + super.setVersion(bInfo.getVersion()); + } + + public GeneratorBundleInfo() { + // TODO Auto-generated constructor stub + } + + // /* (non-Javadoc) + // * @see java.lang.Object#hashCode() + // */ + // public int hashCode() { + // int result = symbolicName == null ? 0 : symbolicName.hashCode(); + // result = result + (version == null ? 0 : version.hashCode()); + // result = result + (location == null ? 0 : location.hashCode()); + // return result; + // } + // + // public String getSymbolicName() { + // return symbolicName; + // } + // + // public String getVersion() { + // return version; + // } + // + // public int expectedState() { + // return expectedState; + // } + // + // public int getStartLevel() { + // return startLevel; + // } + // + // public String getLocation() { + // return location; + // } + // + // public void setSymbolicName(String id) { + // symbolicName = id; + // } + // + // public void setVersion(String version) { + // this.version = version; + // } + // + // public void setExpectedState(int state) { + // expectedState = state; + // } + // + // public void setStartLevel(int level) { + // this.startLevel = level; + // } + // + // public void setLocation(String location) { + // this.location = location; + // } + // + // public void setManifest(String manifest) { + // this.manifest = manifest; + // } + // + // public String getManifest() { + // return manifest; + // } + // + public String getSpecialConfigCommands() { + return specialConfigCommands; + } + + public void setSpecialConfigCommands(String specialConfigCommands) { + this.specialConfigCommands = specialConfigCommands; + } + + public String getSpecialUnconfigCommands() { + return specialUnconfigCommands; + } + + public void setSpecialUnconfigCommands(String specialUnconfigCommands) { + this.specialUnconfigCommands = specialUnconfigCommands; + } + + // /* (non-Javadoc) + // * @see java.lang.Object#equals(java.lang.Object) + // */ + // public boolean equals(Object toCompare) { + // if (toCompare instanceof GeneratorBundleInfo) { + // GeneratorBundleInfo info = (GeneratorBundleInfo) toCompare; + // if (info.symbolicName.equals(symbolicName) && info.version.equals(version) && (info.location == null || location == null ? true : info.location.equals(location))) + // return true; + // } + // return false; + // } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + String superSt = super.toString(); + if (superSt.length() > 0) + buffer.append(superSt.substring(0, superSt.length() - 1)); + buffer.append(", this.specialConfigCommands="); //$NON-NLS-1$ + buffer.append(this.specialConfigCommands); + buffer.append(')'); + return buffer.toString(); + } + + public void initFromManifest(String manifest) { + try { + super.setManifest(manifest); + Headers headers = Headers.parseManifest(new ByteArrayInputStream(manifest.getBytes())); + ManifestElement[] element = ManifestElement.parseHeader("bsn", (String) headers.get(Constants.BUNDLE_SYMBOLICNAME)); //$NON-NLS-1$ + super.setSymbolicName(element[0].getValue()); + super.setVersion((String) headers.get(Constants.BUNDLE_VERSION)); + } catch (BundleException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IProductDescriptor.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IProductDescriptor.java new file mode 100644 index 000000000..ec7f099d8 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IProductDescriptor.java @@ -0,0 +1,42 @@ +package org.eclipse.equinox.internal.p2.publisher; + +import java.util.List; + +public interface IProductDescriptor { + + public String getLauncherName(); + + public List getPlugins(); + + public List getPlugins(boolean includeFragments); + + public List getFragments(); + + public List getFeatures(); + + public boolean containsPlugin(String plugin); + + /** + * Parses the specified url and constructs a feature + */ + public String[] getIcons(); + + public String getConfigIniPath(); + + public String getId(); + + public String getSplashLocation(); + + public String getProductName(); + + public String getApplication(); + + public boolean useFeatures(); + + public String getVersion(); + + public String getVMArguments(String os); + + public String getProgramArguments(String os); + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherInfo.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherInfo.java index f2e24a436..fc8701628 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherInfo.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherInfo.java @@ -9,12 +9,30 @@ ******************************************************************************/ package org.eclipse.equinox.internal.p2.publisher; +import java.util.Collection; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepository; import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepository; public interface IPublisherInfo { /** + * A bitwise flag to say whether or not the index for the artifact repository should + * be updated. + */ + public static final int A_INDEX = 1; + + /** + * A bitwise flag to say whether or the artifacts themselves should be published. + */ + public static final int A_PUBLISH = 2; + + /** + * A bitwise flag to say whether or not to overwrite disk content discovered + * in the repository when publishing an artifact + */ + public static final int A_OVERWRITE = 4; + + /** * Returns the artifact repository into which any publishable artifacts are published * or <code>null</code> if none. * @return a destination artifact repository or <code>null</code> @@ -29,16 +47,16 @@ public interface IPublisherInfo { public IMetadataRepository getMetadataRepository(); /** - * Returns whether or not the artifact repo itself should be published. - * @return <code>true</code> if the artifact repository should be published. - * <code>false</code> otherwise. - */ - public boolean publishArtifactRepository(); - - /** * Returns whether or not artifacts themselves should be published. * @return <code>true</code> if artifacts should be published. * <code>false</code> otherwise. */ - public boolean publishArtifacts(); + public int getArtifactOptions(); + + public IPublishingAdvice getAdvice(String id); + + public void setAdvice(String id, IPublishingAdvice value); + + public Collection getAdviceIds(); + } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherResult.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherResult.java new file mode 100644 index 000000000..642d9dc21 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublisherResult.java @@ -0,0 +1,39 @@ +package org.eclipse.equinox.internal.p2.publisher; + +import java.util.Collection; +import java.util.Map; +import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; + +public interface IPublisherResult { + public static final int MERGE_MATCHING = 0; + public static final int MERGE_ALL_ROOT = 1; + public static final int MERGE_ALL_NON_ROOT = 2; + + public static final String CONFIGURATION_CUS = "CONFIGURATION_CUS"; //$NON-NLS-1$ + + // type markers + public static final String ROOT = "root"; //$NON-NLS-1$ + public static final String NON_ROOT = "non_root"; //$NON-NLS-1$ + + public void addIU(IInstallableUnit iu, String type); + + public void addIUs(Collection ius, String type); + + public void addFragment(String hostId, IInstallableUnit iu); + + /** + * Returns the IUs in this result with the given id. + */ + public Collection getIUs(String id, String type); + + public IInstallableUnit getIU(String id, String type); + + public Collection getFragments(String hostId); + + public Map getFragmentMap(); + + public void merge(IPublisherResult result, int mode); + + // TODO not happy about having this here. Need to figure out a better plan + public Map getConfigData(); +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAction.java index eea4802d5..5ec1ad5f8 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAction.java @@ -10,7 +10,6 @@ package org.eclipse.equinox.internal.p2.publisher; import org.eclipse.core.runtime.IStatus; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.IPublisherResult; public interface IPublishingAction { diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAdvice.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAdvice.java new file mode 100644 index 000000000..dcfcfc838 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/IPublishingAdvice.java @@ -0,0 +1,12 @@ +package org.eclipse.equinox.internal.p2.publisher; + +public interface IPublishingAdvice { + + /** + * Merge the given advice together with this advice. <code>null</code> is returned + * if the advice is incompatible. + * @param advice the advice to merge + * @return the merged advice or <code>null</code> + */ + public IPublishingAdvice merge(IPublishingAdvice advice); +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/InstallPublisher.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/InstallPublisherApplication.java index db3e4dcb1..9a4a8a18e 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/InstallPublisher.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/InstallPublisherApplication.java @@ -11,17 +11,17 @@ package org.eclipse.equinox.internal.p2.publisher; import java.util.ArrayList; import org.eclipse.equinox.internal.p2.publisher.actions.EclipseInstallAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.Generator; -public class InstallPublisher extends AbstractGeneratorApplication { +public class InstallPublisherApplication extends AbstractPublisherApplication { protected String id; protected String version = "1.0.0"; //$NON-NLS-1$ + protected String name; protected String flavor; protected String[] topLevel; protected String[] configurations; - public InstallPublisher() { + public InstallPublisherApplication() { } protected void processParameter(String arg, String parameter, PublisherInfo info) { @@ -33,14 +33,17 @@ public class InstallPublisher extends AbstractGeneratorApplication { if (arg.equalsIgnoreCase("-version")) //$NON-NLS-1$ version = parameter; + if (arg.equalsIgnoreCase("-name")) //$NON-NLS-1$ + name = parameter; + if (arg.equalsIgnoreCase("-flavor")) //$NON-NLS-1$ flavor = parameter; if (arg.equalsIgnoreCase("-top")) //$NON-NLS-1$ - topLevel = Generator.getArrayFromString(parameter, ","); + topLevel = AbstractPublishingAction.getArrayFromString(parameter, ","); if (arg.equalsIgnoreCase("-configs")) //$NON-NLS-1$ - configurations = Generator.getArrayFromString(parameter, ","); + configurations = AbstractPublishingAction.getArrayFromString(parameter, ","); } protected IPublishingAction[] createActions() { @@ -51,6 +54,6 @@ public class InstallPublisher extends AbstractGeneratorApplication { private IPublishingAction createEclipseInstallAction() { String[] exclusions = {"plugins", "features", "configuration"}; - return new EclipseInstallAction(source, id, version, flavor, topLevel, configurations, exclusions); + return new EclipseInstallAction(source, id, version, name, flavor, topLevel, configurations, exclusions); } } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/MetadataGeneratorHelper.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/MetadataGeneratorHelper.java new file mode 100644 index 000000000..ffd2eaf26 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/MetadataGeneratorHelper.java @@ -0,0 +1,1262 @@ +/******************************************************************************* + * 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 + * Genuitec, LLC - added license support + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.eclipse.core.runtime.Path; +import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; +import org.eclipse.equinox.internal.p2.metadata.ArtifactKey; +import org.eclipse.equinox.internal.p2.metadata.InstallableUnit; +import org.eclipse.equinox.internal.p2.publisher.features.*; +import org.eclipse.equinox.internal.provisional.frameworkadmin.BundleInfo; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.ArtifactDescriptor; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactDescriptor; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.processing.ProcessingStepDescriptor; +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.osgi.service.environment.EnvironmentInfo; +import org.eclipse.osgi.service.resolver.*; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.*; + +public class MetadataGeneratorHelper { + /** + * A capability namespace representing the type of Eclipse resource (bundle, feature, source bundle, etc) + * @see RequiredCapability#getNamespace() + */ + public static final String NAMESPACE_ECLIPSE_TYPE = "org.eclipse.equinox.p2.eclipse.type"; //$NON-NLS-1$ + + /** + * A capability name in the {@link #NAMESPACE_ECLIPSE_TYPE} namespace + * representing and OSGi bundle resource + * @see RequiredCapability#getName() + */ + public static final String TYPE_ECLIPSE_BUNDLE = "bundle"; //$NON-NLS-1$ + /** + * A capability name in the {@link #NAMESPACE_ECLIPSE_TYPE} namespace + * representing a feature + * @see RequiredCapability#getName() + */ + public static final String TYPE_ECLIPSE_FEATURE = "feature"; //$NON-NLS-1$ + + /** + * A capability name in the {@link #NAMESPACE_ECLIPSE_TYPE} namespace + * representing a source bundle + * @see RequiredCapability#getName() + */ + public static final String TYPE_ECLIPSE_SOURCE = "source"; //$NON-NLS-1$ + + /** + * A capability name in the {@link #NAMESPACE_ECLIPSE_TYPE} namespace + * representing localized manifest properties + * @see RequiredCapability#getName() + */ + public static final String TYPE_ECLIPSE_MANIFEST_LOCALIZATION = "manifest.localization"; //$NON-NLS-1$ + + // Only certain properties in the bundle manifest are assumed to be localized. + public static final String[] BUNDLE_LOCALIZED_PROPERTIES = {Constants.BUNDLE_NAME, Constants.BUNDLE_DESCRIPTION, Constants.BUNDLE_VENDOR, Constants.BUNDLE_CONTACTADDRESS, Constants.BUNDLE_DOCURL, Constants.BUNDLE_UPDATELOCATION}; + public static final int BUNDLE_LOCALIZATION_INDEX = BUNDLE_LOCALIZED_PROPERTIES.length; + + private static final String[] BUNDLE_IU_PROPERTY_MAP = {Constants.BUNDLE_NAME, IInstallableUnit.PROP_NAME, Constants.BUNDLE_DESCRIPTION, IInstallableUnit.PROP_DESCRIPTION, Constants.BUNDLE_VENDOR, IInstallableUnit.PROP_PROVIDER, Constants.BUNDLE_CONTACTADDRESS, IInstallableUnit.PROP_CONTACT, Constants.BUNDLE_DOCURL, IInstallableUnit.PROP_DOC_URL}; + + private static final String CAPABILITY_NS_JAVA_PACKAGE = "java.package"; //$NON-NLS-1$ + private static final String CAPABILITY_NS_OSGI_BUNDLE = "osgi.bundle"; //$NON-NLS-1$ + private static final String CAPABILITY_NS_OSGI_FRAGMENT = "osgi.fragment"; //$NON-NLS-1$ + + private static final String CAPABILITY_NS_UPDATE_FEATURE = "org.eclipse.update.feature"; //$NON-NLS-1$ + + private static final Version DEFAULT_JRE_VERSION = new Version("1.6"); //$NON-NLS-1$ + + public static final String ECLIPSE_FEATURE_CLASSIFIER = "org.eclipse.update.feature"; //$NON-NLS-1$ + public static final String OSGI_BUNDLE_CLASSIFIER = "osgi.bundle"; //$NON-NLS-1$ + public static final String BINARY_ARTIFACT_CLASSIFIER = "binary"; //$NON-NLS-1$ + + public static final String INSTALL_FEATURES_FILTER = "(org.eclipse.update.install.features=true)"; //$NON-NLS-1$ + + private static final String IU_NAMESPACE = IInstallableUnit.NAMESPACE_IU_ID; + + private static final String LAUNCHER_ID_PREFIX = "org.eclipse.launcher"; //$NON-NLS-1$ + + private static final String ECLIPSE_INSTALL_HANDLER_PROP = "org.eclipse.update.installHandler"; //$NON-NLS-1$ + + //TODO - need to come up with a way to infer launcher version + private static final Version LAUNCHER_VERSION = new Version(1, 0, 0); + + private static final Version versionMax = new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + + public static final TouchpointType TOUCHPOINT_NATIVE = MetadataFactory.createTouchpointType("org.eclipse.equinox.p2.native", new Version(1, 0, 0)); //$NON-NLS-1$ + public static final TouchpointType TOUCHPOINT_OSGI = MetadataFactory.createTouchpointType("org.eclipse.equinox.p2.osgi", new Version(1, 0, 0)); //$NON-NLS-1$ + + public static final ProvidedCapability BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, new Version(1, 0, 0)); + public static final ProvidedCapability FEATURE_CAPABILITY = MetadataFactory.createProvidedCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_FEATURE, new Version(1, 0, 0)); + public static final ProvidedCapability SOURCE_BUNDLE_CAPABILITY = MetadataFactory.createProvidedCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_SOURCE, new Version(1, 0, 0)); + public static final ProvidedCapability MANIFEST_LOCALIZATION_CAPABILITY = MetadataFactory.createProvidedCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_MANIFEST_LOCALIZATION, new Version(1, 0, 0)); + + static final String DEFAULT_BUNDLE_LOCALIZATION = "plugin"; //$NON-NLS-1$ + static final String PROPERTIES_FILE_EXTENSION = ".properties"; //$NON-NLS-1$ + static final String MANIFEST_LOCALIZATIONS = "eclipse.p2.manifest.localizations"; //$NON-NLS-1$ + + static final Locale DEFAULT_LOCALE = new Locale("df", "LT"); //$NON-NLS-1$//$NON-NLS-2$ + static final Locale PSEUDO_LOCALE = new Locale("zz", "ZZ"); //$NON-NLS-1$//$NON-NLS-2$ + + public static IArtifactDescriptor createArtifactDescriptor(IArtifactKey key, File pathOnDisk, boolean asIs, boolean recur) { + //TODO this size calculation is bogus + ArtifactDescriptor result = new ArtifactDescriptor(key); + if (pathOnDisk != null) { + result.setProperty(IArtifactDescriptor.ARTIFACT_SIZE, Long.toString(pathOnDisk.length())); + // TODO - this is wrong but I'm testing a work-around for bug 205842 + result.setProperty(IArtifactDescriptor.DOWNLOAD_SIZE, Long.toString(pathOnDisk.length())); + } + return result; + } + + public static IArtifactDescriptor createPack200ArtifactDescriptor(IArtifactKey key, File pathOnDisk, String installSize) { + final String PACKED_FORMAT = "packed"; //$NON-NLS-1$ + //TODO this size calculation is bogus + ArtifactDescriptor result = new ArtifactDescriptor(key); + if (pathOnDisk != null) { + result.setProperty(IArtifactDescriptor.ARTIFACT_SIZE, installSize); + // TODO - this is wrong but I'm testing a work-around for bug 205842 + result.setProperty(IArtifactDescriptor.DOWNLOAD_SIZE, Long.toString(pathOnDisk.length())); + } + ProcessingStepDescriptor[] steps = new ProcessingStepDescriptor[] {new ProcessingStepDescriptor("org.eclipse.equinox.p2.processing.Pack200Unpacker", null, true)}; //$NON-NLS-1$ + result.setProcessingSteps(steps); + result.setProperty(IArtifactDescriptor.FORMAT, PACKED_FORMAT); + return result; + } + + public static IArtifactKey createBundleArtifactKey(String bsn, String version) { + return new ArtifactKey(OSGI_BUNDLE_CLASSIFIER, bsn, new Version(version)); + } + + public static IInstallableUnit createIUFragment(String id, String version, String flavor, String configSpec, Map touchpointData) { + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String resultId = flavor + AbstractPublishingAction.createIdString(configSpec) + id; + cu.setId(resultId); + Version resultVersion = new Version(version); + cu.setVersion(resultVersion); + + cu.setFilter(AbstractPublishingAction.createFilterSpec(configSpec)); + cu.setHost(new RequiredCapability[] {MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, id, new VersionRange(resultVersion, true, resultVersion, true), null, false, false)}); + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {MetadataGeneratorHelper.createSelfCapability(resultId, resultVersion)}); + + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + return MetadataFactory.createInstallableUnit(cu); + } + + public static IInstallableUnit createBundleConfigurationUnit(String iuId, Version iuVersion, boolean isBundleFragment, GeneratorBundleInfo configInfo, String configurationFlavor, String filter) { + if (configInfo == null) + return null; + + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = configurationFlavor + iuId; + cu.setId(configUnitId); + cu.setVersion(iuVersion); + + //Indicate the IU to which this CU apply + cu.setHost(new RequiredCapability[] { // + MetadataFactory.createRequiredCapability(CAPABILITY_NS_OSGI_BUNDLE, iuId, new VersionRange(iuVersion, true, versionMax, true), null, false, false), // + MetadataFactory.createRequiredCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, new VersionRange(new Version(1, 0, 0), true, new Version(2, 0, 0), false), null, false, false)}); + + //Adds capabilities for fragment, self, and describing the flavor supported + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {createSelfCapability(configUnitId, iuVersion), MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_FLAVOR, configurationFlavor, new Version(1, 0, 0))}); + + Map touchpointData = new HashMap(); + touchpointData.put("install", "installBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("uninstall", "uninstallBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("configure", createConfigScript(configInfo, isBundleFragment)); //$NON-NLS-1$ + touchpointData.put("unconfigure", createUnconfigScript(configInfo, isBundleFragment)); //$NON-NLS-1$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + cu.setFilter(filter); + return MetadataFactory.createInstallableUnit(cu); + } + + public static IInstallableUnit createBundleIU(BundleDescription bd, Map manifest, boolean isFolderPlugin, IArtifactKey key, Set localizationIUs) { + IInstallableUnit bundleIU = createBundleIU(bd, manifest, isFolderPlugin, key); + + if (manifest != null && bd.getLocation() != null) { + String bundleLocalization = (String) manifest.get(Constants.BUNDLE_LOCALIZATION); + if (bundleLocalization == null) { + bundleLocalization = DEFAULT_BUNDLE_LOCALIZATION; + } + Map manifestLocalizations = getManifestLocalizations(manifest, new File(bd.getLocation())); + if (manifestLocalizations != null) { + localizationIUs.addAll(createLocalizationFragmentsForBundle(bd, manifestLocalizations)); + } + } + return bundleIU; + } + + public static IInstallableUnit createBundleIU(BundleDescription bd, Map manifest, boolean isFolderPlugin, IArtifactKey key) { + boolean isBinaryBundle = true; + if (manifest != null && manifest.containsKey("Eclipse-SourceBundle")) { //$NON-NLS-1$ + isBinaryBundle = false; + } + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + iu.setSingleton(bd.isSingleton()); + iu.setId(bd.getSymbolicName()); + iu.setVersion(bd.getVersion()); + iu.setFilter(bd.getPlatformFilter()); + + iu.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(bd.getSymbolicName(), new VersionRange(new Version(0, 0, 0), true, bd.getVersion(), false), IUpdateDescriptor.NORMAL, null)); + + boolean isFragment = bd.getHost() != null; + // boolean requiresAFragment = isFragment ? false : requireAFragment(bd, manifest); + + //Process the required bundles + BundleSpecification requiredBundles[] = bd.getRequiredBundles(); + ArrayList reqsDeps = new ArrayList(); + // if (requiresAFragment) + // reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_TYPE_OSGI_FRAGMENTS, bd.getSymbolicName(), VersionRange.emptyRange, null, false, false)); + if (isFragment) + reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_NS_OSGI_BUNDLE, bd.getHost().getName(), bd.getHost().getVersionRange(), null, false, false)); + for (int j = 0; j < requiredBundles.length; j++) + reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_NS_OSGI_BUNDLE, requiredBundles[j].getName(), requiredBundles[j].getVersionRange() == VersionRange.emptyRange ? null : requiredBundles[j].getVersionRange(), null, requiredBundles[j].isOptional(), false)); + + // Process the import packages + ImportPackageSpecification osgiImports[] = bd.getImportPackages(); + for (int i = 0; i < osgiImports.length; i++) { + // TODO we need to sort out how we want to handle wild-carded dynamic imports - for now we ignore them + ImportPackageSpecification importSpec = osgiImports[i]; + String importPackageName = importSpec.getName(); + if (importPackageName.indexOf('*') != -1) + continue; + + VersionRange versionRange = importSpec.getVersionRange() == VersionRange.emptyRange ? null : importSpec.getVersionRange(); + + //TODO this needs to be refined to take into account all the attribute handled by imports + reqsDeps.add(MetadataFactory.createRequiredCapability(CAPABILITY_NS_JAVA_PACKAGE, importPackageName, versionRange, null, isOptional(importSpec), false)); + } + iu.setRequiredCapabilities((RequiredCapability[]) reqsDeps.toArray(new RequiredCapability[reqsDeps.size()])); + + // Create set of provided capabilities + ArrayList providedCapabilities = new ArrayList(); + providedCapabilities.add(createSelfCapability(bd.getSymbolicName(), bd.getVersion())); + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_OSGI_BUNDLE, bd.getSymbolicName(), bd.getVersion())); + + // Process the export package + ExportPackageDescription exports[] = bd.getExportPackages(); + for (int i = 0; i < exports.length; i++) { + //TODO make sure that we support all the refinement on the exports + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_JAVA_PACKAGE, exports[i].getName(), exports[i].getVersion() == Version.emptyVersion ? null : exports[i].getVersion())); + } + // Here we add a bundle capability to identify bundles + if (isBinaryBundle) + providedCapabilities.add(BUNDLE_CAPABILITY); + else + providedCapabilities.add(SOURCE_BUNDLE_CAPABILITY); + + if (isFragment) + providedCapabilities.add(MetadataFactory.createProvidedCapability(CAPABILITY_NS_OSGI_FRAGMENT, bd.getHost().getName(), bd.getVersion())); + iu.setCapabilities((ProvidedCapability[]) providedCapabilities.toArray(new ProvidedCapability[providedCapabilities.size()])); + + iu.setArtifacts(new IArtifactKey[] {key}); + + iu.setTouchpointType(TOUCHPOINT_OSGI); + + // Set certain properties from the manifest header attributes as IU properties. + // The values of these attributes may be localized (strings starting with '%') + // with the translated values appearing in the localization IU fragments + // associated with the bundle IU. + if (manifest != null) { + int i = 0; + while (i < BUNDLE_IU_PROPERTY_MAP.length) { + if (manifest.containsKey(BUNDLE_IU_PROPERTY_MAP[i])) { + String value = (String) manifest.get(BUNDLE_IU_PROPERTY_MAP[i]); + if (value != null && value.length() > 0) { + iu.setProperty(BUNDLE_IU_PROPERTY_MAP[i + 1], value); + } + } + i += 2; + } + } + + // Define the immutable metadata for this IU. In this case immutable means + // that this is something that will not impact the configuration. + Map touchpointData = new HashMap(); + if (isFolderPlugin) + touchpointData.put("zipped", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("manifest", toManifestString(manifest)); //$NON-NLS-1$ + iu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + + return MetadataFactory.createInstallableUnit(iu); + } + + private static List createLocalizationFragmentsForBundle(BundleDescription bd, Map manifestLocalizations) { + List localizationFragments = new ArrayList(manifestLocalizations.size()); + for (Iterator iter = manifestLocalizations.keySet().iterator(); iter.hasNext();) { + Locale locale = (Locale) iter.next(); + Properties localizedStrings = (Properties) manifestLocalizations.get(locale); + IInstallableUnitFragment nextLocaleFragment = createLocalizationFragmentOfBundle(bd, locale, localizedStrings); + localizationFragments.add(nextLocaleFragment); + } + return localizationFragments; + } + + /* + * @param bd + * @param locale + * @param localizedStrings + * @return installableUnitFragment + */ + private static IInstallableUnitFragment createLocalizationFragmentOfBundle(BundleDescription bd, Locale locale, Properties localizedStrings) { + InstallableUnitFragmentDescription fragment = new MetadataFactory.InstallableUnitFragmentDescription(); + String fragmentId = makeLocalizationFragmentId(bd.getSymbolicName(), locale); + fragment.setId(fragmentId); + fragment.setVersion(bd.getVersion()); + + RequiredCapability[] hostReqs = new RequiredCapability[] {MetadataFactory.createRequiredCapability(NAMESPACE_ECLIPSE_TYPE, bd.getSymbolicName(), new VersionRange(bd.getVersion(), true, bd.getVersion(), true), null, false, false)}; + fragment.setHost(hostReqs); + + fragment.setSingleton(true); + + Enumeration propertyKeys = localizedStrings.propertyNames(); + while (propertyKeys.hasMoreElements()) { + String nextKey = (String) propertyKeys.nextElement(); + fragment.setProperty(nextKey, localizedStrings.getProperty(nextKey)); + } + // TODO: do we need any capabilities? + // Create set of provided capabilities It's just a tag indicating a localization fragment. + ArrayList providedCapabilities = new ArrayList(1); + providedCapabilities.add(MANIFEST_LOCALIZATION_CAPABILITY); + fragment.setCapabilities((ProvidedCapability[]) providedCapabilities.toArray(new ProvidedCapability[providedCapabilities.size()])); + + return MetadataFactory.createInstallableUnitFragment(fragment); + } + + public static void createHostLocalizationFragments(BundleDescription bd, String hostId, String[] hostBundleManifestValues, Set localizationIUs) { + Map hostLocalizations = getHostLocalizations(new File(bd.getLocation()), hostBundleManifestValues); + + for (Iterator iter = hostLocalizations.keySet().iterator(); iter.hasNext();) { + Locale locale = (Locale) iter.next(); + Properties localizedStrings = (Properties) hostLocalizations.get(locale); + IInstallableUnitFragment nextLocaleFragment = createLocalizationFragmentOfHost(hostId, hostBundleManifestValues, bd, locale, localizedStrings); + localizationIUs.add(nextLocaleFragment); + } + } + + /* + * @param hostId + * @param bd + * @param locale + * @param localizedStrings + * @return installableUnitFragment + */ + private static IInstallableUnitFragment createLocalizationFragmentOfHost(String hostId, String[] hostManifestValues, BundleDescription bd, Locale locale, Properties localizedStrings) { + InstallableUnitFragmentDescription fragment = new MetadataFactory.InstallableUnitFragmentDescription(); + HostSpecification hostSpec = bd.getHost(); + String fragmentId = makeLocalizationFragmentId(hostId, locale); + fragment.setId(fragmentId); + fragment.setVersion(bd.getVersion()); // TODO: is this a meaningful version? + + RequiredCapability[] hostReqs = new RequiredCapability[] {MetadataFactory.createRequiredCapability(NAMESPACE_ECLIPSE_TYPE, hostSpec.getName(), hostSpec.getVersionRange(), null, false, false)}; + fragment.setHost(hostReqs); + + fragment.setSingleton(true); + + for (int i = 0; i < BUNDLE_LOCALIZED_PROPERTIES.length; i++) { + String nextKey = hostManifestValues[i]; + String localizedValue = null; + if (nextKey != null && (localizedValue = localizedStrings.getProperty(nextKey)) != null) { + fragment.setProperty(nextKey, localizedValue); + } + } + // TODO: do we need any capabilities? It's just a tag indicating a localization fragment. + // Create set of provided capabilities + ArrayList providedCapabilities = new ArrayList(1); + providedCapabilities.add(MANIFEST_LOCALIZATION_CAPABILITY); + fragment.setCapabilities((ProvidedCapability[]) providedCapabilities.toArray(new ProvidedCapability[providedCapabilities.size()])); + + return MetadataFactory.createInstallableUnitFragment(fragment); + } + + /** + * @param id + * @param locale + * @return the id for the fragment contain the localized properties + * for the manifest of the bundle with the given id + * in the given locale. + */ + private static String makeLocalizationFragmentId(String id, Locale locale) { + String localeString = (!DEFAULT_LOCALE.equals(locale) ? '_' + locale.toString() : ""); //$NON-NLS-1$ + return id + "_manifest" + localeString + "_properties"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Creates an IU corresponding to an update site category + * @param category The category descriptor + * @param featureIUs The IUs of the features that belong to the category + * @param parentCategory The parent category, or <code>null</code> + * @return an IU representing the category + */ + public static IInstallableUnit createCategoryIU(SiteCategory category, Set featureIUs, IInstallableUnit parentCategory) { + InstallableUnitDescription cat = new MetadataFactory.InstallableUnitDescription(); + cat.setSingleton(true); + cat.setId(category.getName()); + cat.setVersion(Version.emptyVersion); + cat.setProperty(IInstallableUnit.PROP_NAME, category.getLabel()); + cat.setProperty(IInstallableUnit.PROP_DESCRIPTION, category.getDescription()); + + ArrayList reqsConfigurationUnits = new ArrayList(featureIUs.size()); + for (Iterator iterator = featureIUs.iterator(); iterator.hasNext();) { + IInstallableUnit iu = (IInstallableUnit) iterator.next(); + VersionRange range = new VersionRange(iu.getVersion(), true, iu.getVersion(), true); + reqsConfigurationUnits.add(MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, iu.getId(), range, iu.getFilter(), false, false)); + } + //note that update sites don't currently support nested categories, but it may be useful to add in the future + if (parentCategory != null) { + reqsConfigurationUnits.add(MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, parentCategory.getId(), VersionRange.emptyRange, parentCategory.getFilter(), false, false)); + } + cat.setRequiredCapabilities((RequiredCapability[]) reqsConfigurationUnits.toArray(new RequiredCapability[reqsConfigurationUnits.size()])); + cat.setCapabilities(new ProvidedCapability[] {MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, category.getName(), Version.emptyVersion)}); + cat.setArtifacts(new IArtifactKey[0]); + cat.setProperty(IInstallableUnit.PROP_TYPE_CATEGORY, "true"); //$NON-NLS-1$ + return MetadataFactory.createInstallableUnit(cat); + } + + private static String createConfigScript(GeneratorBundleInfo configInfo, boolean isBundleFragment) { + if (configInfo == null) + return ""; //$NON-NLS-1$ + + String configScript = "";//$NON-NLS-1$ + if (!isBundleFragment && configInfo.getStartLevel() != BundleInfo.NO_LEVEL) { + configScript += "setStartLevel(startLevel:" + configInfo.getStartLevel() + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if (!isBundleFragment && configInfo.isMarkedAsStarted()) { + configScript += "markStarted(started: true);"; //$NON-NLS-1$ + } + + if (configInfo.getSpecialConfigCommands() != null) { + configScript += configInfo.getSpecialConfigCommands(); + } + + return configScript; + } + + private static String createDefaultBundleConfigScript(GeneratorBundleInfo configInfo) { + return createConfigScript(configInfo, false); + } + + public static IInstallableUnit createDefaultBundleConfigurationUnit(GeneratorBundleInfo configInfo, GeneratorBundleInfo unconfigInfo, String configurationFlavor) { + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = createDefaultConfigUnitId(OSGI_BUNDLE_CLASSIFIER, configurationFlavor); + cu.setId(configUnitId); + Version configUnitVersion = new Version(1, 0, 0); + cu.setVersion(configUnitVersion); + + // Add capabilities for fragment, self, and describing the flavor supported + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {createSelfCapability(configUnitId, configUnitVersion), MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_FLAVOR, configurationFlavor, new Version(1, 0, 0))}); + + // Create a required capability on bundles + RequiredCapability[] reqs = new RequiredCapability[] {MetadataFactory.createRequiredCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_BUNDLE, VersionRange.emptyRange, null, false, true)}; + cu.setHost(reqs); + Map touchpointData = new HashMap(); + + touchpointData.put("install", "installBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("uninstall", "uninstallBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("configure", createDefaultBundleConfigScript(configInfo)); //$NON-NLS-1$ + touchpointData.put("unconfigure", createDefaultBundleUnconfigScript(unconfigInfo)); //$NON-NLS-1$ + + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + return MetadataFactory.createInstallableUnit(cu); + } + + private static String createDefaultBundleUnconfigScript(GeneratorBundleInfo unconfigInfo) { + return createUnconfigScript(unconfigInfo, false); + } + + public static String createDefaultConfigUnitId(String classifier, String configurationFlavor) { + return configurationFlavor + "." + classifier + ".default"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + public static IInstallableUnit createDefaultFeatureConfigurationUnit(String configurationFlavor) { + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = createDefaultConfigUnitId(ECLIPSE_FEATURE_CLASSIFIER, configurationFlavor); + cu.setId(configUnitId); + Version configUnitVersion = new Version(1, 0, 0); + cu.setVersion(configUnitVersion); + + // Add capabilities for fragment, self, and describing the flavor supported + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {createSelfCapability(configUnitId, configUnitVersion), MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_FLAVOR, configurationFlavor, new Version(1, 0, 0))}); + + // Create a required capability on features + RequiredCapability[] reqs = new RequiredCapability[] {MetadataFactory.createRequiredCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_FEATURE, VersionRange.emptyRange, null, true, true)}; + cu.setHost(reqs); + + cu.setFilter(INSTALL_FEATURES_FILTER); + Map touchpointData = new HashMap(); + touchpointData.put("install", "installFeature(feature:${artifact},featureId:default,featureVersion:default)"); //$NON-NLS-1$//$NON-NLS-2$ + touchpointData.put("uninstall", "uninstallFeature(feature:${artifact},featureId:default,featureVersion:default)"); //$NON-NLS-1$//$NON-NLS-2$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + + return MetadataFactory.createInstallableUnit(cu); + } + + public static IInstallableUnit createDefaultConfigurationUnitForSourceBundles(String configurationFlavor) { + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = createDefaultConfigUnitId("source", configurationFlavor); //$NON-NLS-1$ + cu.setId(configUnitId); + Version configUnitVersion = new Version(1, 0, 0); + cu.setVersion(configUnitVersion); + + // Add capabilities for fragment, self, and describing the flavor supported + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {createSelfCapability(configUnitId, configUnitVersion), MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_FLAVOR, configurationFlavor, new Version(1, 0, 0))}); + + // Create a required capability on source providers + RequiredCapability[] reqs = new RequiredCapability[] {MetadataFactory.createRequiredCapability(NAMESPACE_ECLIPSE_TYPE, TYPE_ECLIPSE_SOURCE, VersionRange.emptyRange, null, true, true)}; + cu.setHost(reqs); + Map touchpointData = new HashMap(); + + touchpointData.put("install", "addSourceBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + touchpointData.put("uninstall", "removeSourceBundle(bundle:${artifact})"); //$NON-NLS-1$ //$NON-NLS-2$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + return MetadataFactory.createInstallableUnit(cu); + } + + private static void addExtraProperties(IInstallableUnit iiu, Properties extraProperties) { + if (iiu instanceof InstallableUnit) { + InstallableUnit iu = (InstallableUnit) iiu; + + for (Enumeration e = extraProperties.propertyNames(); e.hasMoreElements();) { + String name = (String) e.nextElement(); + iu.setProperty(name, extraProperties.getProperty(name)); + } + } + } + + public static IInstallableUnit[] createEclipseIU(BundleDescription bd, Map manifest, boolean isFolderPlugin, IArtifactKey key, Properties extraProperties) { + ArrayList iusCreated = new ArrayList(4); + + IInstallableUnit iu = createBundleIU(bd, manifest, isFolderPlugin, key); + addExtraProperties(iu, extraProperties); + iusCreated.add(iu); + + if (manifest != null) { + String bundleLocalization = null; + if (bd.getHost() == null) // not a fragment + bundleLocalization = (String) manifest.get(Constants.BUNDLE_LOCALIZATION); + if (bundleLocalization == null) + bundleLocalization = DEFAULT_BUNDLE_LOCALIZATION; + + Map manifestLocalizations = getManifestLocalizations(manifest, new File(bd.getLocation())); + + if (manifestLocalizations != null) { + List localizationFragments = createLocalizationFragmentsForBundle(bd, manifestLocalizations); + for (Iterator iter = localizationFragments.iterator(); iter.hasNext();) { + addExtraProperties((IInstallableUnit) iter.next(), extraProperties); + } + iusCreated.addAll(localizationFragments); + } + } + + return (IInstallableUnit[]) (iusCreated.toArray(new IInstallableUnit[iusCreated.size()])); + } + + public static IArtifactKey createFeatureArtifactKey(String fsn, String version) { + return new ArtifactKey(ECLIPSE_FEATURE_CLASSIFIER, fsn, new Version(version)); + } + + public static IInstallableUnit createFeatureJarIU(Feature feature, boolean isExploded) { + return createFeatureJarIU(feature, null, isExploded, null); + } + + public static IInstallableUnit createFeatureJarIU(Feature feature, ArrayList childIUs, boolean isExploded, Properties extraProperties) { + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + String id = getTransformedId(feature.getId(), /*isPlugin*/false, /*isGroup*/false); + iu.setId(id); + Version version = new Version(feature.getVersion()); + iu.setVersion(version); + if (feature.getLicense() != null) + iu.setLicense(new License(feature.getLicenseURL(), feature.getLicense())); + if (feature.getCopyright() != null) + iu.setCopyright(new Copyright(feature.getCopyrightURL(), feature.getCopyright())); + + // The required capabilities are not specified at this level because we don't want the feature jar to be attractive to install. + + iu.setTouchpointType(TOUCHPOINT_OSGI); + iu.setFilter(INSTALL_FEATURES_FILTER); + iu.setSingleton(true); + + if (feature.getInstallHandler() != null) { + String installHandlerProperty = "handler=" + feature.getInstallHandler(); //$NON-NLS-1$ + + if (feature.getInstallHandlerLibrary() != null) + installHandlerProperty += ", library=" + feature.getInstallHandlerLibrary(); //$NON-NLS-1$ + + if (feature.getInstallHandlerURL() != null) + installHandlerProperty += ", url=" + feature.getInstallHandlerURL(); //$NON-NLS-1$ + + iu.setProperty(ECLIPSE_INSTALL_HANDLER_PROP, installHandlerProperty); + } + + iu.setCapabilities(new ProvidedCapability[] {createSelfCapability(id, version), FEATURE_CAPABILITY, MetadataFactory.createProvidedCapability(CAPABILITY_NS_UPDATE_FEATURE, feature.getId(), version)}); + iu.setArtifacts(new IArtifactKey[] {createFeatureArtifactKey(feature.getId(), version.toString())}); + + // link in all the children (if any) as requirements. + // TODO consider if these should be linked as exact version numbers. Should be ok but may be brittle. + if (childIUs != null) { + RequiredCapability[] required = new RequiredCapability[childIUs.size()]; + for (int i = 0; i < childIUs.size(); i++) { + IInstallableUnit child = (IInstallableUnit) childIUs.get(i); + required[i] = MetadataFactory.createRequiredCapability(IU_NAMESPACE, child.getId(), new VersionRange(child.getVersion(), true, child.getVersion(), true), INSTALL_FEATURES_FILTER, false, false); + } + iu.setRequiredCapabilities(required); + } + + if (isExploded) { + // Define the immutable metadata for this IU. In this case immutable means + // that this is something that will not impact the configuration. + Map touchpointData = new HashMap(); + touchpointData.put("zipped", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + iu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + } + + if (extraProperties != null) { + Enumeration e = extraProperties.propertyNames(); + while (e.hasMoreElements()) { + String name = (String) e.nextElement(); + iu.setProperty(name, extraProperties.getProperty(name)); + } + } + + return MetadataFactory.createInstallableUnit(iu); + } + + // moved to FeaturesAction + public static IInstallableUnit createGroupIU(Feature feature, IInstallableUnit featureIU) { + return createGroupIU(feature, featureIU, null); + } + + // moved to FeaturesAction + public static IInstallableUnit createGroupIU(Feature feature, IInstallableUnit featureIU, Properties extraProperties) { + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + String id = getTransformedId(feature.getId(), /*isPlugin*/false, /*isGroup*/true); + iu.setId(id); + Version version = new Version(feature.getVersion()); + iu.setVersion(version); + iu.setProperty(IInstallableUnit.PROP_NAME, feature.getLabel()); + if (feature.getLicense() != null) + iu.setLicense(new License(feature.getLicenseURL(), feature.getLicense())); + if (feature.getCopyright() != null) + iu.setCopyright(new Copyright(feature.getCopyrightURL(), feature.getCopyright())); + iu.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(id, new VersionRange(new Version(0, 0, 0), true, new Version(feature.getVersion()), false), IUpdateDescriptor.NORMAL, null)); + + FeatureEntry entries[] = feature.getEntries(); + RequiredCapability[] required = new RequiredCapability[entries.length + 1]; + for (int i = 0; i < entries.length; i++) { + VersionRange range = getVersionRange(entries[i]); + required[i] = MetadataFactory.createRequiredCapability(IU_NAMESPACE, getTransformedId(entries[i].getId(), entries[i].isPlugin(), /*isGroup*/true), range, getFilter(entries[i]), entries[i].isOptional(), false); + } + required[entries.length] = MetadataFactory.createRequiredCapability(IU_NAMESPACE, featureIU.getId(), new VersionRange(featureIU.getVersion(), true, featureIU.getVersion(), true), INSTALL_FEATURES_FILTER, false, false); + iu.setRequiredCapabilities(required); + iu.setTouchpointType(TouchpointType.NONE); + iu.setProperty(IInstallableUnit.PROP_TYPE_GROUP, Boolean.TRUE.toString()); + // TODO: shouldn't the filter for the group be constructed from os, ws, arch, nl + // of the feature? + // iu.setFilter(filter); + iu.setCapabilities(new ProvidedCapability[] {createSelfCapability(id, version)}); + + if (extraProperties != null) { + Enumeration e = extraProperties.propertyNames(); + while (e.hasMoreElements()) { + String name = (String) e.nextElement(); + iu.setProperty(name, extraProperties.getProperty(name)); + } + } + + return MetadataFactory.createInstallableUnit(iu); + } + + /** + * Creates IUs and artifact descriptors for the JRE. The resulting IUs are added + * to the given set, and the resulting artifact descriptor, if any, is returned. + * If the jreLocation is <code>null</code>, default information is generated. + */ + public static IArtifactDescriptor createJREData(File jreLocation, IPublisherResult results) { + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + iu.setSingleton(false); + String id = "a.jre"; //$NON-NLS-1$ + Version version = DEFAULT_JRE_VERSION; + iu.setId(id); + iu.setVersion(version); + iu.setTouchpointType(TOUCHPOINT_NATIVE); + + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configId = "config." + id;//$NON-NLS-1$ + cu.setId(configId); + cu.setVersion(version); + cu.setHost(new RequiredCapability[] {MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, id, new VersionRange(version, true, versionMax, true), null, false, false)}); + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {createSelfCapability(configId, version)}); + cu.setTouchpointType(TOUCHPOINT_NATIVE); + Map touchpointData = new HashMap(); + + if (jreLocation == null || !jreLocation.exists()) { + //set some reasonable defaults + iu.setVersion(version); + iu.setCapabilities(generateJRECapability(id, version, null)); + results.addIU(MetadataFactory.createInstallableUnit(iu), IPublisherResult.ROOT); + + touchpointData.put("install", ""); //$NON-NLS-1$ //$NON-NLS-2$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + results.addIU(MetadataFactory.createInstallableUnit(cu), IPublisherResult.ROOT); + return null; + } + generateJREIUData(iu, id, version, jreLocation); + + //Generate artifact for JRE + IArtifactKey key = new ArtifactKey(BINARY_ARTIFACT_CLASSIFIER, id, version); + iu.setArtifacts(new IArtifactKey[] {key}); + results.addIU(MetadataFactory.createInstallableUnit(iu), IPublisherResult.ROOT); + + //Create config info for the CU + String configurationData = "unzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ + touchpointData.put("install", configurationData); //$NON-NLS-1$ + String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ + touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + results.addIU(MetadataFactory.createInstallableUnit(cu), IPublisherResult.ROOT); + + //Create the artifact descriptor + return createArtifactDescriptor(key, jreLocation, false, true); + } + + public static ArtifactKey createLauncherArtifactKey(String id, Version version) { + return new ArtifactKey(BINARY_ARTIFACT_CLASSIFIER, id, version); + } + + /** + * Creates IUs and artifacts for the Launcher executable. The resulting IUs are added + * to the given set, and the resulting artifact descriptor is returned. + */ + public static IArtifactDescriptor createLauncherIU(File launcher, String configurationFlavor, IPublisherResult resultantIUs) { + if (launcher == null || !launcher.exists()) + return null; + + //Create the IU + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + iu.setSingleton(true); + String launcherId = LAUNCHER_ID_PREFIX + '_' + launcher.getName(); + iu.setId(launcherId); + iu.setVersion(LAUNCHER_VERSION); + + IArtifactKey key = createLauncherArtifactKey(launcherId, LAUNCHER_VERSION); + iu.setArtifacts(new IArtifactKey[] {key}); + iu.setCapabilities(new ProvidedCapability[] {createSelfCapability(launcherId, LAUNCHER_VERSION)}); + iu.setTouchpointType(TOUCHPOINT_NATIVE); + resultantIUs.addIU(MetadataFactory.createInstallableUnit(iu), IPublisherResult.ROOT); + + //Create the CU + InstallableUnitFragmentDescription cu = new InstallableUnitFragmentDescription(); + String configUnitId = configurationFlavor + launcherId; + cu.setId(configUnitId); + cu.setVersion(LAUNCHER_VERSION); + cu.setHost(new RequiredCapability[] {MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, launcherId, new VersionRange(LAUNCHER_VERSION, true, versionMax, true), null, false, false)}); + cu.setProperty(IInstallableUnit.PROP_TYPE_FRAGMENT, Boolean.TRUE.toString()); + cu.setCapabilities(new ProvidedCapability[] {createSelfCapability(configUnitId, LAUNCHER_VERSION)}); + cu.setTouchpointType(TOUCHPOINT_NATIVE); + Map touchpointData = new HashMap(); + String configurationData = "unzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ + EnvironmentInfo info = (EnvironmentInfo) ServiceHelper.getService(Activator.getContext(), EnvironmentInfo.class.getName()); + if (!info.getOS().equals(org.eclipse.osgi.service.environment.Constants.OS_WIN32)) { + if (info.getOS().equals(org.eclipse.osgi.service.environment.Constants.OS_MACOSX)) { + configurationData += " chmod(targetDir:${installFolder}/Eclipse.app/Contents/MacOS, targetFile:eclipse, permissions:755);"; //$NON-NLS-1$ + String config = AbstractPublishingAction.createConfigSpec(null, "macosx", null); + generateLauncherSetter("Eclipse", launcherId, LAUNCHER_VERSION, config, resultantIUs); + } else + configurationData += " chmod(targetDir:${installFolder}, targetFile:" + launcher.getName() + ", permissions:755);"; //$NON-NLS-1$ //$NON-NLS-2$ + } else { + String config = AbstractPublishingAction.createConfigSpec(null, "win32", null); + generateLauncherSetter("eclipse", launcherId, LAUNCHER_VERSION, config, resultantIUs); + } + touchpointData.put("install", configurationData); //$NON-NLS-1$ + String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ + touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$ + cu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + resultantIUs.addIU(MetadataFactory.createInstallableUnitFragment(cu), IPublisherResult.ROOT); + + //Create the artifact descriptor + return createArtifactDescriptor(key, launcher, false, true); + } + + public static void generateLauncherSetter(String launcherName, String iuId, Version version, String configSpec, IPublisherResult result) { + InstallableUnitDescription iud = new MetadataFactory.InstallableUnitDescription(); + String id = iuId + '.' + launcherName; + iud.setId(id); + iud.setVersion(version); + iud.setTouchpointType(MetadataGeneratorHelper.TOUCHPOINT_OSGI); + iud.setCapabilities(new ProvidedCapability[] {MetadataGeneratorHelper.createSelfCapability(id, version)}); + + String filter = AbstractPublishingAction.createFilterSpec(configSpec); + if (filter.length() > 0) + iud.setFilter(filter); + Map touchpointData = new HashMap(); + touchpointData.put("configure", "setLauncherName(name:" + launcherName + ")"); + touchpointData.put("unconfigure", "setLauncherName()"); + iud.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + result.addIU(MetadataFactory.createInstallableUnit(iud), IPublisherResult.ROOT); + } + + public static ProvidedCapability createSelfCapability(String installableUnitId, Version installableUnitVersion) { + return MetadataFactory.createProvidedCapability(IU_NAMESPACE, installableUnitId, installableUnitVersion); + } + + private static String createUnconfigScript(GeneratorBundleInfo unconfigInfo, boolean isBundleFragment) { + if (unconfigInfo == null) + return ""; //$NON-NLS-1$ + String unconfigScript = "";//$NON-NLS-1$ + if (!isBundleFragment && unconfigInfo.getStartLevel() != BundleInfo.NO_LEVEL) { + unconfigScript += "setStartLevel(startLevel:" + BundleInfo.NO_LEVEL + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if (!isBundleFragment && unconfigInfo.isMarkedAsStarted()) { + unconfigScript += "markStarted(started: false);"; //$NON-NLS-1$ + } + + if (unconfigInfo.getSpecialUnconfigCommands() != null) { + unconfigScript += unconfigInfo.getSpecialUnconfigCommands(); + } + return unconfigScript; + + } + + private static ProvidedCapability[] generateJRECapability(String installableUnitId, Version installableUnitVersion, InputStream profileStream) { + if (profileStream == null) { + //use the 1.6 profile stored in the generator bundle + try { + profileStream = Activator.getContext().getBundle().getEntry("/profiles/JavaSE-1.6.profile").openStream(); //$NON-NLS-1$ + } catch (IOException e) { + throw new RuntimeException(e); + } + } + Properties p = new Properties(); + try { + p.load(profileStream); + ManifestElement[] jrePackages = ManifestElement.parseHeader("org.osgi.framework.system.packages", (String) p.get("org.osgi.framework.system.packages")); //$NON-NLS-1$ //$NON-NLS-2$ + ProvidedCapability[] exportedPackageAsCapabilities = new ProvidedCapability[jrePackages.length + 1]; + exportedPackageAsCapabilities[0] = createSelfCapability(installableUnitId, installableUnitVersion); + for (int i = 1; i <= jrePackages.length; i++) { + exportedPackageAsCapabilities[i] = MetadataFactory.createProvidedCapability(CAPABILITY_NS_JAVA_PACKAGE, jrePackages[i - 1].getValue(), null); + } + return exportedPackageAsCapabilities; + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (BundleException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + if (profileStream != null) { + try { + profileStream.close(); + } catch (IOException e) { + //ignore secondary failure + } + } + } + return new ProvidedCapability[0]; + } + + private static void generateJREIUData(InstallableUnitDescription iu, String installableUnitId, Version installableUnitVersion, File jreLocation) { + //Look for a JRE profile file to set version and capabilities + File[] profiles = jreLocation.listFiles(new FileFilter() { + public boolean accept(File pathname) { + return pathname.getAbsolutePath().endsWith(".profile"); //$NON-NLS-1$ + } + }); + if (profiles.length != 1) { + iu.setVersion(DEFAULT_JRE_VERSION); + iu.setCapabilities(generateJRECapability(installableUnitId, installableUnitVersion, null)); + return; + } + String profileName = profiles[0].getAbsolutePath().substring(profiles[0].getAbsolutePath().lastIndexOf('/')); + Version version = DEFAULT_JRE_VERSION; + //TODO Find a better way to determine JRE version + if (profileName.indexOf("1.6") > 0) { //$NON-NLS-1$ + version = new Version("1.6"); //$NON-NLS-1$ + } else if (profileName.indexOf("1.5") > 0) { //$NON-NLS-1$ + version = new Version("1.5"); //$NON-NLS-1$ + } else if (profileName.indexOf("1.4") > 0) { //$NON-NLS-1$ + version = new Version("1.4"); //$NON-NLS-1$ + } + iu.setVersion(version); + try { + iu.setCapabilities(generateJRECapability(installableUnitId, installableUnitVersion, new FileInputStream(profiles[0]))); + } catch (FileNotFoundException e) { + //Shouldn't happen, but ignore and fall through to use default + } + } + + // moved to FeatureAction + public static String getFilter(FeatureEntry entry) { + StringBuffer result = new StringBuffer(); + result.append("(&"); //$NON-NLS-1$ + if (entry.getFilter() != null) + result.append(entry.getFilter()); + if (entry.getOS() != null) + result.append("(osgi.os=" + entry.getOS() + ')');//$NON-NLS-1$ + if (entry.getWS() != null) + result.append("(osgi.ws=" + entry.getWS() + ')');//$NON-NLS-1$ + if (entry.getArch() != null) + result.append("(osgi.arch=" + entry.getArch() + ')');//$NON-NLS-1$ + if (entry.getNL() != null) + result.append("(osgi.nl=" + entry.getNL() + ')');//$NON-NLS-1$ + if (result.length() == 2) + return null; + result.append(')'); + return result.toString(); + } + + // moved to FeatureAction + public static String getTransformedId(String original, boolean isPlugin, boolean isGroup) { + return (isPlugin ? original : original + (isGroup ? ".feature.group" : ".feature.jar")); //$NON-NLS-1$//$NON-NLS-2$ + } + + // moved to FeatureAction + public static VersionRange getVersionRange(FeatureEntry entry) { + String versionSpec = entry.getVersion(); + if (versionSpec == null) + // TODO should really be returning VersionRange.emptyRange here... + return null; + Version version = new Version(versionSpec); + if (!entry.isRequires()) + return new VersionRange(version, true, version, true); + String match = entry.getMatch(); + if (match == null) + // TODO should really be returning VersionRange.emptyRange here... + return null; + if (match.equals("perfect")) //$NON-NLS-1$ + return new VersionRange(version, true, version, true); + if (match.equals("equivalent")) { //$NON-NLS-1$ + Version upper = new Version(version.getMajor(), version.getMinor() + 1, 0); + return new VersionRange(version, true, upper, false); + } + if (match.equals("compatible")) { //$NON-NLS-1$ + Version upper = new Version(version.getMajor() + 1, 0, 0); + return new VersionRange(version, true, upper, false); + } + if (match.equals("greaterOrEqual")) //$NON-NLS-1$ + return new VersionRange(version, true, new VersionRange(null).getMaximum(), true); + return null; + } + + private static boolean isOptional(ImportPackageSpecification importedPackage) { + if (importedPackage.getDirective(Constants.RESOLUTION_DIRECTIVE).equals(ImportPackageSpecification.RESOLUTION_DYNAMIC) || importedPackage.getDirective(Constants.RESOLUTION_DIRECTIVE).equals(ImportPackageSpecification.RESOLUTION_OPTIONAL)) + return true; + return false; + } + + private static String toManifestString(Map p) { + if (p == null) + return null; + Collection properties = p.entrySet(); + StringBuffer result = new StringBuffer(); + for (Iterator iterator = properties.iterator(); iterator.hasNext();) { + Map.Entry aProperty = (Map.Entry) iterator.next(); + if (aProperty.getKey().equals(BundleDescriptionFactory.BUNDLE_SHAPE)) + continue; + result.append(aProperty.getKey()).append(": ").append(aProperty.getValue()).append('\n'); //$NON-NLS-1$ + } + return result.toString(); + } + + // Return a map from locale to property set for the manifest localizations + // from the given bundle directory and given bundle localization path/name + // manifest property value. + private static Map getManifestLocalizations(Map manifest, File bundleLocation) { + Map localizations; + Locale defaultLocale = null; // = Locale.ENGLISH; // TODO: get this from GeneratorInfo + String[] bundleManifestValues = getManifestCachedValues(manifest); + String bundleLocalization = bundleManifestValues[BUNDLE_LOCALIZATION_INDEX]; + + if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && //$NON-NLS-1$ + bundleLocation.isFile()) { + localizations = getJarManifestLocalization(bundleLocation, bundleLocalization, defaultLocale, bundleManifestValues); + } else { + localizations = getDirManifestLocalization(bundleLocation, bundleLocalization, defaultLocale, bundleManifestValues); + } + + return localizations; + } + + public static String[] getManifestCachedValues(Map manifest) { + String[] cachedValues = new String[BUNDLE_LOCALIZED_PROPERTIES.length + 1]; + for (int j = 0; j < MetadataGeneratorHelper.BUNDLE_LOCALIZED_PROPERTIES.length; j++) { + String value = (String) manifest.get(BUNDLE_LOCALIZED_PROPERTIES[j]); + if (value != null && value.length() > 1 && value.charAt(0) == '%') { + cachedValues[j] = value.substring(1); + } + } + String localizationFile = (String) manifest.get(org.osgi.framework.Constants.BUNDLE_LOCALIZATION); + cachedValues[BUNDLE_LOCALIZATION_INDEX] = (localizationFile != null ? localizationFile : DEFAULT_BUNDLE_LOCALIZATION); + return cachedValues; + } + + // Return a map from locale to property set for the manifest localizations + // from the given bundle directory and given bundle localization path/name + // manifest property value. + public static Map getHostLocalizations(File bundleLocation, String[] hostBundleManifestValues) { + Map localizations; + Locale defaultLocale = null; // = Locale.ENGLISH; // TODO: get this from GeneratorInfo + String hostBundleLocalization = hostBundleManifestValues[BUNDLE_LOCALIZATION_INDEX]; + + if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && //$NON-NLS-1$ + bundleLocation.isFile()) { + localizations = getJarManifestLocalization(bundleLocation, hostBundleLocalization, defaultLocale, hostBundleManifestValues); + } else { + localizations = getDirManifestLocalization(bundleLocation, hostBundleLocalization, defaultLocale, hostBundleManifestValues); + } + + return localizations; + } + + private static Map getJarManifestLocalization(File bundleLocation, String bundleLocalization, Locale defaultLocale, String[] bundleManifestValues) { + ZipFile jarFile = null; + Map localizations = new HashMap(4); + try { + jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); + for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { + ZipEntry nextEntry = (ZipEntry) entries.nextElement(); + String nextName = nextEntry.getName(); + String localeString = getLocaleString(nextName, bundleLocalization); + + if (!nextEntry.isDirectory() && localeString != null) { + Locale nextLocale = getLocale(localeString); + InputStream stream = null; + try { + stream = jarFile.getInputStream(nextEntry); + Properties properties = new Properties(); + properties.load(stream); + Properties localizedStrings = getLocalizedProperties(bundleManifestValues, properties); + if (localizedStrings.size() > 0) { + localizations.put(nextLocale, localizedStrings); + if (DEFAULT_LOCALE.equals(nextLocale) && defaultLocale != null) { + localizations.put(nextLocale, localizedStrings); + } + } + } finally { + if (stream != null) + stream.close(); + } + } + } + } catch (IOException ioe) { + ioe.printStackTrace(); + } finally { + if (jarFile != null) { + try { + jarFile.close(); + } catch (IOException ioe) { + // do nothing + } + } + } + + return localizations; + } + + private static Map getDirManifestLocalization(File bundleLocation, String bundleLocalization, Locale defaultLocale, String[] hostBundleManifestValues) { + File localizationPath = new File(bundleLocation, bundleLocalization); + File localizationDir = localizationPath.getParentFile(); + final String localizationFile = localizationPath.getName(); + MetadataGeneratorHelper foo = new MetadataGeneratorHelper(); + String[] localizationFiles = localizationDir.list(foo.new LocalizationFileFilter() { + public boolean accept(File directory, String filename) { + return (getLocaleString(filename, localizationFile) != null ? true : false); + } + }); + + HashMap localizations = null; + + if (localizationFiles != null) { + localizations = new HashMap(localizationFiles.length); + for (int i = 0; i < localizationFiles.length; i++) { + String nextFile = localizationFiles[i]; + Locale nextLocale = getLocale(getLocaleString(nextFile, localizationFile)); + + try { + Properties properties = loadProperties(bundleLocation, nextFile); + Properties localizedStrings = getLocalizedProperties(hostBundleManifestValues, properties); + if (localizedStrings.size() > 0) { + localizations.put(nextLocale, localizedStrings); + if (DEFAULT_LOCALE.equals(nextLocale) && defaultLocale != null) { + localizations.put(nextLocale, localizedStrings); + } + } + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + } + + return localizations; + } + + private abstract class LocalizationFileFilter implements FilenameFilter { + + public LocalizationFileFilter() { + // Nothing to do + } + + /* (non-Javadoc) + * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) + */ + public abstract boolean accept(File directory, String filename); + } + + static public String getLocaleString(String filename, String filenamePrefix) { + String localeString = null; + if (filename.startsWith(filenamePrefix) && filename.endsWith(PROPERTIES_FILE_EXTENSION)) { + if (filename.length() > filenamePrefix.length() + PROPERTIES_FILE_EXTENSION.length()) { + localeString = filename.substring(filenamePrefix.length() + 1, filename.length() - PROPERTIES_FILE_EXTENSION.length()); + } else { + localeString = ""; //$NON-NLS-1$ + } + } + return localeString; + } + + private static Properties loadProperties(File bundleLocation, String localizationFile) throws IOException { + Properties result = new Properties(); + InputStream propertyStream = null; + try { + try { + if (bundleLocation.isDirectory()) + propertyStream = new FileInputStream(new File(bundleLocation, localizationFile)); + else { + URLConnection connection = new URL("jar:" + bundleLocation.toURL().toExternalForm() + "!/" + localizationFile).openConnection(); //$NON-NLS-1$ //$NON-NLS-2$ + connection.setUseCaches(false); + propertyStream = connection.getInputStream(); + } + } catch (FileNotFoundException e) { + // if there is no messages file then just return; + return result; + } + result.load(propertyStream); + } finally { + if (propertyStream != null) + propertyStream.close(); + } + return result; + } + + static private Locale getLocale(String localeString) { + Locale locale = DEFAULT_LOCALE; + if (localeString.length() == 5 && localeString.indexOf('_') == 2) { + locale = new Locale(localeString.substring(0, 2), localeString.substring(3, 5)); + } else if (localeString.length() == 2) { + locale = new Locale(localeString.substring(0, 2)); + } + return locale; + } + + static private Properties getLocalizedProperties(String[] bundleManifestKeys, Properties properties) { + Properties localizedProperties = new Properties(); + for (int i = 0; i < BUNDLE_LOCALIZED_PROPERTIES.length; i++) { + String key = bundleManifestKeys[i]; + if (key != null) { + String localizedValue = properties.getProperty(key); + if (localizedValue != null) + localizedProperties.put(key, localizedValue); + } + } + return localizedProperties; + } + + public static Object[] createFeatureRootFileIU(String featureId, String featureVersion, File location, FileSetDescriptor descriptor) { + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + iu.setSingleton(true); + String id = featureId + '_' + descriptor.getKey(); + iu.setId(id); + Version version = new Version(featureVersion); + iu.setVersion(version); + iu.setCapabilities(new ProvidedCapability[] {createSelfCapability(id, version)}); + iu.setTouchpointType(TOUCHPOINT_NATIVE); + String configSpec = descriptor.getConfigSpec(); + if (configSpec != null) + iu.setFilter(AbstractPublishingAction.createFilterSpec(configSpec)); + File[] fileResult = attachFiles(iu, descriptor, location); + setupLinks(iu, descriptor); + setupPermissions(iu, descriptor); + + IInstallableUnit iuResult = MetadataFactory.createInstallableUnit(iu); + // need to return both the iu and any files. + return new Object[] {iuResult, fileResult}; + } + + // attach the described files from the given location to the given iu description. Return + // the list of files identified. + private static File[] attachFiles(InstallableUnitDescription iu, FileSetDescriptor descriptor, File location) { + String fileList = descriptor.getFiles(); + String[] fileSpecs = getArrayFromString(fileList, ","); //$NON-NLS-1$ + File[] files = new File[fileSpecs.length]; + if (fileSpecs.length > 0) { + for (int i = 0; i < fileSpecs.length; i++) { + String spec = fileSpecs[i]; + if (spec.startsWith("file:")) + spec = spec.substring(5); + files[i] = new File(location, spec); + } + } + // add touchpoint actions to unzip and cleanup as needed + // TODO need to support fancy root file location specs + Map touchpointData = new HashMap(2); + String configurationData = "unzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ + touchpointData.put("install", configurationData); //$NON-NLS-1$ + String unConfigurationData = "cleanupzip(source:@artifact, target:${installFolder});"; //$NON-NLS-1$ + touchpointData.put("uninstall", unConfigurationData); //$NON-NLS-1$ + iu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + + // prime the IU with an artifact key that will correspond to the zipped up root files. + IArtifactKey key = createLauncherArtifactKey(iu.getId(), iu.getVersion()); + iu.setArtifacts(new IArtifactKey[] {key}); + return files; + } + + private static void setupPermissions(InstallableUnitDescription iu, FileSetDescriptor descriptor) { + Map touchpointData = new HashMap(); + String[][] permsList = descriptor.getPermissions(); + for (int i = 0; i < permsList.length; i++) { + String[] permSpec = permsList[i]; + String configurationData = " chmod(targetDir:${installFolder}, targetFile:" + permSpec[1] + ", permissions:" + permSpec[0] + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + touchpointData.put("install", configurationData); //$NON-NLS-1$ + iu.addTouchpointData(MetadataFactory.createTouchpointData(touchpointData)); + } + } + + private static void setupLinks(InstallableUnitDescription iu, FileSetDescriptor descriptor) { + // TODO setup the link support. + } + + 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()]); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/Publisher.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/Publisher.java index 8f9e5b2c5..b84d08a14 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/Publisher.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/Publisher.java @@ -12,8 +12,6 @@ package org.eclipse.equinox.internal.p2.publisher; import java.util.Collection; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.IPublisherResult; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.PublisherResult; import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepository; public class Publisher { diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherInfo.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherInfo.java index 33e3ee683..d08b264c2 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherInfo.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherInfo.java @@ -9,15 +9,28 @@ ******************************************************************************/ package org.eclipse.equinox.internal.p2.publisher; +import java.util.*; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepository; import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepository; public class PublisherInfo implements IPublisherInfo { - private boolean publishArtifacts = false; - private boolean publishArtifactRepository = false; + private int artifactOptions = 0; private IMetadataRepository metadataRepository; private IArtifactRepository artifactRepository; + private Map adviceMap = new HashMap(11); + + public IPublishingAdvice getAdvice(String id) { + return (IPublishingAdvice) adviceMap.get(id); + } + + public void setAdvice(String id, IPublishingAdvice value) { + adviceMap.put(id, value); + } + + public Collection getAdviceIds() { + return adviceMap.keySet(); + } public IArtifactRepository getArtifactRepository() { return artifactRepository; @@ -27,12 +40,8 @@ public class PublisherInfo implements IPublisherInfo { return metadataRepository; } - public boolean publishArtifactRepository() { - return publishArtifactRepository; - } - - public boolean publishArtifacts() { - return publishArtifacts; + public int getArtifactOptions() { + return artifactOptions; } public void setArtifactRepository(IArtifactRepository value) { @@ -43,12 +52,8 @@ public class PublisherInfo implements IPublisherInfo { metadataRepository = value; } - public void setPublishArtifactRepository(boolean value) { - publishArtifactRepository = value; - } - - public void setPublishArtifacts(boolean value) { - publishArtifacts = value; + public void setArtifactOptions(int value) { + artifactOptions = value; } public String getSummary() { diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherResult.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherResult.java new file mode 100644 index 000000000..03eba964c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/PublisherResult.java @@ -0,0 +1,158 @@ +package org.eclipse.equinox.internal.p2.publisher; + +import java.util.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; + +public class PublisherResult implements IPublisherResult { + // type markers + public static final String ROOT = "root"; //$NON-NLS-1$ + public static final String NON_ROOT = "non_root"; //$NON-NLS-1$ + public static final String FRAGMENT = "fragment"; //$NON-NLS-1$ + + // The set of top level IUs + final Map rootIUs = new HashMap(); + + // The set of internal and leaf IUs + final Map nonRootIUs = new HashMap(); + + // Map of IU id to a set of fragments for that IU + final Map fragmentMap = new HashMap(); + + // map of os, ws, arch to ConfigData objects + private final Map configData = new HashMap(11); + + public void addIU(IInstallableUnit iu, String type) { + if (type == ROOT) + addIU(rootIUs, iu.getId(), iu); + if (type == NON_ROOT) + addIU(nonRootIUs, iu.getId(), iu); + } + + public void addIUs(Collection ius, String type) { + for (Iterator i = ius.iterator(); i.hasNext();) { + IInstallableUnit iu = (IInstallableUnit) i.next(); + addIU(iu, type); + } + } + + public void addFragment(String hostId, IInstallableUnit iu) { + addIU(fragmentMap, hostId, iu); + } + + public Map getFragmentMap() { + return fragmentMap; + } + + public Collection getFragments(String hostId) { + return Arrays.asList((IInstallableUnit[]) fragmentMap.get(hostId)); + } + + private void addIU(Map map, String id, IInstallableUnit iu) { + IInstallableUnit[] ius = (IInstallableUnit[]) map.get(id); + if (ius == null) { + ius = new IInstallableUnit[] {iu}; + map.put(id, ius); + } else { + IInstallableUnit[] newIUs = new IInstallableUnit[ius.length + 1]; + System.arraycopy(ius, 0, newIUs, 0, ius.length); + newIUs[ius.length] = iu; + map.put(id, newIUs); + } + } + + /** + * Returns all IUs generated during this execution of the generator. + */ + public Map getGeneratedIUs(String type) { + if (type == null) { + HashMap all = new HashMap(); + all.putAll(rootIUs); + all.putAll(nonRootIUs); + return all; + } + if (type == ROOT) + return rootIUs; + if (type == NON_ROOT) + return nonRootIUs; + throw new IllegalArgumentException("Invalid IU type: " + type); //$NON-NLS-1$ + } + + // TODO this method really should not be needed as it just returns the first + // matching IU non-deterministically. + public IInstallableUnit getIU(String id, String type) { + if (type == null || type == ROOT) { + IInstallableUnit[] ius = (IInstallableUnit[]) rootIUs.get(id); + if (ius != null && ius.length > 0) + return ius[0]; + } + if (type == null || type == NON_ROOT) { + IInstallableUnit[] ius = (IInstallableUnit[]) nonRootIUs.get(id); + if (ius != null && ius.length > 0) + return ius[0]; + } + return null; + } + + /** + * Returns the IUs in this result with the given id. + */ + public Collection getIUs(String id, String type) { + if (type == null) { + ArrayList result = new ArrayList(); + result.addAll(id == null ? flatten(rootIUs.values()) : Arrays.asList((Object[]) rootIUs.get(id))); + result.addAll(id == null ? flatten(nonRootIUs.values()) : Arrays.asList((Object[]) nonRootIUs.get(id))); + return result; + } + if (type == ROOT) + return id == null ? flatten(rootIUs.values()) : Arrays.asList((Object[]) rootIUs.get(id)); + if (type == NON_ROOT) + return id == null ? flatten(nonRootIUs.values()) : Arrays.asList((Object[]) nonRootIUs.get(id)); + return null; + } + + private List flatten(Collection values) { + ArrayList result = new ArrayList(); + for (Iterator i = values.iterator(); i.hasNext();) { + IInstallableUnit[] ius = (IInstallableUnit[]) i.next(); + for (int j = 0; j < ius.length; j++) + result.add(ius[j]); + } + return result; + } + + public Map getConfigData() { + return configData; + } + + public void merge(IPublisherResult result, int mode) { + // merge non-conditional pieces + fragmentMap.putAll(result.getFragmentMap()); + configData.putAll(result.getConfigData()); + // mergeAdvice(result); + + if (mode == MERGE_MATCHING) { + addIUs(result.getIUs(null, ROOT), ROOT); + addIUs(result.getIUs(null, NON_ROOT), NON_ROOT); + } else if (mode == MERGE_ALL_ROOT) { + addIUs(result.getIUs(null, ROOT), ROOT); + addIUs(result.getIUs(null, NON_ROOT), ROOT); + } else if (mode == MERGE_ALL_NON_ROOT) { + addIUs(result.getIUs(null, ROOT), NON_ROOT); + addIUs(result.getIUs(null, NON_ROOT), NON_ROOT); + } + } + + // private void mergeAdvice(IPublisherResult result) { + // for (Iterator i = result.getAdviceIds().iterator(); i.hasNext();) { + // String id = (String) i.next(); + // IPublishingAdvice advice = result.getAdvice(id); + // if (advice == null) + // continue; + // IPublishingAdvice thisAdvice = getAdvice(id); + // if (thisAdvice == null) + // adviceMap.put(id, advice); + // else + // adviceMap.put(id, thisAdvice.merge(advice)); + // } + // } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/AccumulateConfigDataAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/AccumulateConfigDataAction.java index d7be913c5..10eebc091 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/AccumulateConfigDataAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/AccumulateConfigDataAction.java @@ -10,34 +10,147 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import java.io.File; +import java.io.IOException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; +import org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxConstants; +import org.eclipse.equinox.internal.frameworkadmin.equinox.EquinoxFwConfigFileParser; +import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; +import org.eclipse.equinox.internal.p2.publisher.*; +import org.eclipse.equinox.internal.provisional.frameworkadmin.*; +import org.osgi.framework.*; +import org.osgi.service.packageadmin.PackageAdmin; +import org.osgi.util.tracker.ServiceTracker; -public class AccumulateConfigDataAction extends Generator implements IPublishingAction { +public class AccumulateConfigDataAction extends AbstractPublishingAction { - private String config; + private final static String FILTER_OBJECTCLASS = "(" + Constants.OBJECTCLASS + "=" + FrameworkAdmin.class.getName() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + private final static String filterFwName = "(" + FrameworkAdmin.SERVICE_PROP_KEY_FW_NAME + "=Equinox)"; //$NON-NLS-1$ //$NON-NLS-2$ + //String filterFwVersion = "(" + FrameworkAdmin.SERVICE_PROP_KEY_FW_VERSION + "=" + props.getProperty("equinox.fw.version") + ")"; + private final static String filterLauncherName = "(" + FrameworkAdmin.SERVICE_PROP_KEY_LAUNCHER_NAME + "=Eclipse.exe)"; //$NON-NLS-1$ //$NON-NLS-2$ + //String filterLauncherVersion = "(" + FrameworkAdmin.SERVICE_PROP_KEY_LAUNCHER_VERSION + "=" + props.getProperty("equinox.launcher.version") + ")"; + private final static String frameworkAdminFillter = "(&" + FILTER_OBJECTCLASS + filterFwName + filterLauncherName + ")"; //$NON-NLS-1$ //$NON-NLS-2$ - public AccumulateConfigDataAction(IPublisherInfo info, String config, File configurationLocation, File executableLocation) { - super(createGeneratorInfo(info, configurationLocation, executableLocation)); - this.config = config; - } + private static final String ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_MANIPULATOR = "org.eclipse.equinox.simpleconfigurator.manipulator"; //$NON-NLS-1$ + private static final String ORG_ECLIPSE_EQUINOX_FRAMEWORKADMIN_EQUINOX = "org.eclipse.equinox.frameworkadmin.equinox"; //$NON-NLS-1$ + + private String configSpec; + private File configurationLocation; + private Manipulator manipulator; + private ServiceTracker frameworkAdminTracker; + private File executableLocation; - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info, File configurationLocation, File executableLocation) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - result.initializeFrameworkManipulator(configurationLocation, executableLocation); - return result; + public AccumulateConfigDataAction(IPublisherInfo info, String configSpec, File configurationLocation, File executableLocation) { + this.configSpec = configSpec; + this.configurationLocation = configurationLocation; + this.executableLocation = executableLocation; } public IStatus perform(IPublisherInfo info, IPublisherResult results) { - storeConfigData(results, config); + initializeFrameworkManipulator(configurationLocation, executableLocation); + storeConfigData(info, configSpec, results); return Status.OK_STATUS; } + protected void storeConfigData(IPublisherInfo info, String configSpec, IPublisherResult result) { + if (result.getConfigData().containsKey(configSpec)) + return; //been here, done this + + File fwConfigFile = new File(configurationLocation, EquinoxConstants.CONFIG_INI); + if (fwConfigFile.exists()) { + ConfigData data = loadConfigData(fwConfigFile); + result.getConfigData().put(configSpec, data); + } + } + + public void initializeFrameworkManipulator(File config, File executable) { + createFrameworkManipulator(); + + LauncherData launcherData = manipulator.getLauncherData(); + launcherData.setFwPersistentDataLocation(config, true); + launcherData.setLauncher(executable); + try { + manipulator.load(); + } catch (IllegalStateException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } catch (FrameworkAdminRuntimeException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } catch (IOException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } + } + + public ConfigData loadConfigData(File location) { + if (manipulator == null) + return null; + + EquinoxFwConfigFileParser parser = new EquinoxFwConfigFileParser(Activator.getContext()); + try { + parser.readFwConfig(manipulator, location); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return manipulator.getConfigData(); + } + + public LauncherData getLauncherData() { + return manipulator == null ? null : manipulator.getLauncherData(); + } + + /** + * Obtains the framework manipulator instance. Throws an exception + * if it could not be created. + */ + protected void createFrameworkManipulator() { + FrameworkAdmin admin = getFrameworkAdmin(); + if (admin == null) + throw new RuntimeException("Framework admin service not found"); //$NON-NLS-1$ + manipulator = admin.getManipulator(); + if (manipulator == null) + throw new RuntimeException("Framework manipulator not found"); //$NON-NLS-1$ + } + + private FrameworkAdmin getFrameworkAdmin() { + if (frameworkAdminTracker == null) { + try { + Filter filter = Activator.getContext().createFilter(frameworkAdminFillter); + frameworkAdminTracker = new ServiceTracker(Activator.getContext(), filter, null); + frameworkAdminTracker.open(); + } catch (InvalidSyntaxException e) { + // never happens + } + } + FrameworkAdmin admin = (FrameworkAdmin) frameworkAdminTracker.getService(); + if (admin == null) { + startBundle(ORG_ECLIPSE_EQUINOX_FRAMEWORKADMIN_EQUINOX); + startBundle(ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR_MANIPULATOR); + admin = (FrameworkAdmin) frameworkAdminTracker.getService(); + } + return admin; + } + + private boolean startBundle(String bundleId) { + PackageAdmin packageAdmin = (PackageAdmin) ServiceHelper.getService(Activator.getContext(), PackageAdmin.class.getName()); + if (packageAdmin == null) + return false; + + Bundle[] bundles = packageAdmin.getBundles(bundleId, null); + if (bundles != null && bundles.length > 0) { + for (int i = 0; i < bundles.length; i++) { + try { + if ((bundles[0].getState() & Bundle.RESOLVED) > 0) { + bundles[0].start(); + return true; + } + } catch (BundleException e) { + // failed, try next bundle + } + } + } + return false; + } } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundleAdvice.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundleAdvice.java new file mode 100644 index 000000000..ffb8ad78b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundleAdvice.java @@ -0,0 +1,70 @@ +package org.eclipse.equinox.internal.p2.publisher.actions; + +import java.util.*; +import org.eclipse.equinox.internal.p2.publisher.IPublishingAdvice; + +public class BundleAdvice implements IBundleAdvice { + + Map shapes = new HashMap(11); + + public String getShape(String id, String version) { + Object[] values = (Object[]) shapes.get(id); + // if no one says anything then don't say anything. someone else might have an opinion + if (values == null) + return null; + + // otherwise if the object is mentioned, assume its shape is DIR + for (int i = 0; i < values.length; i++) { + if (values[i].equals(version)) + return IBundleAdvice.DIR; + } + // if no one says anything then don't say anything. someone else might have an opinion + return null; + } + + public void setShape(String id, String version, String shape) { + Object[] values = (Object[]) shapes.get(id); + if (values == null) { + values = new Object[] {version}; + shapes.put(id, values); + } else { + Object[] newObjects = new Object[values.length + 1]; + System.arraycopy(values, 0, newObjects, 0, values.length); + newObjects[values.length] = version; + shapes.put(id, newObjects); + } + } + + public IPublishingAdvice merge(IPublishingAdvice advice) { + if (!(advice instanceof BundleAdvice)) + return this; + BundleAdvice source = (BundleAdvice) advice; + for (Iterator i = source.shapes.keySet().iterator(); i.hasNext();) { + String id = (String) i.next(); + Object[] myValues = (Object[]) shapes.get(id); + Object[] sourceValues = (Object[]) source.shapes.get(id); + if (myValues == null) + shapes.put(id, sourceValues); + else if (sourceValues != null) + shapes.put(id, merge(myValues, sourceValues)); + } + return this; + } + + private Object[] merge(Object[] myValues, Object[] sourceValues) { + List result = Arrays.asList(myValues); + for (int i = 0; i < sourceValues.length; i++) { + Object object = sourceValues[i]; + boolean found = false; + for (Iterator j = result.iterator(); j.hasNext();) { + if (j.next().equals(object)) { + found = true; + break; + } + } + if (!found) + result.add(object); + } + return (Object[]) result.toArray(new Object[result.size()]); + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundlesAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundlesAction.java index 43b3e20f5..d045b45d9 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundlesAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/BundlesAction.java @@ -10,39 +10,40 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import java.io.File; -import java.util.ArrayList; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; -import org.eclipse.osgi.service.resolver.BundleDescription; +import java.io.IOException; +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; +import org.eclipse.equinox.internal.p2.publisher.*; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactDescriptor; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepository; +import org.eclipse.equinox.internal.provisional.p2.metadata.IArtifactKey; +import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; +import org.eclipse.osgi.service.resolver.*; /** * Publish IUs for all of the bundles in the given set of locations. The locations can * be actual locations of the bundles or folders of bundles. */ -public class BundlesAction extends Generator implements IPublishingAction { +public class BundlesAction extends AbstractPublishingAction { + + protected static final String ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR = "org.eclipse.equinox.simpleconfigurator"; //$NON-NLS-1$ + protected static final String ORG_ECLIPSE_UPDATE_CONFIGURATOR = "org.eclipse.update.configurator"; //$NON-NLS-1$ private File[] locations; + private StateObjectFactory stateObjectFactory; - public BundlesAction(File[] locations, IPublisherInfo info) { - super(createGeneratorInfo(info)); + public BundlesAction(File[] locations) { this.locations = expandLocations(locations); - } - - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - return result; + // TODO need to figure a better way of configuring the generator... + PlatformAdmin platformAdmin = (PlatformAdmin) ServiceHelper.getService(Activator.getContext(), PlatformAdmin.class.getName()); + if (platformAdmin != null) + stateObjectFactory = platformAdmin.getFactory(); } public IStatus perform(IPublisherInfo info, IPublisherResult results) { BundleDescription[] bundles = getBundleDescriptions(locations); - generateBundleIUs(bundles, results, info.getArtifactRepository()); + generateBundleIUs(bundles, results, info); return Status.OK_STATUS; } @@ -63,4 +64,128 @@ public class BundlesAction extends Generator implements IPublishingAction { return (File[]) result.toArray(new File[result.size()]); } + protected void generateBundleIUs(BundleDescription[] bundles, IPublisherResult result, IPublisherInfo info) { + // Computing the path for localized property files in a NL fragment bundle + // requires the BUNDLE_LOCALIZATION property from the manifest of the host bundle, + // so a first pass is done over all the bundles to cache this value as well as the tags + // from the manifest for the localizable properties. + final int CACHE_PHASE = 0; + final int GENERATE_PHASE = 1; + final int BUNDLE_LOCALIZATION_INDEX = MetadataGeneratorHelper.BUNDLE_LOCALIZATION_INDEX; + Map bundleLocalizationMap = new HashMap(bundles.length); + Set localizationIUs = new HashSet(32); + for (int phase = CACHE_PHASE; phase <= GENERATE_PHASE; phase++) { + for (int i = 0; i < bundles.length; i++) { + BundleDescription bd = bundles[i]; + // A bundle may be null if the associated plug-in does not have a manifest file - + // for example, org.eclipse.jdt.launching.j9 + if (bd != null && bd.getSymbolicName() != null && bd.getVersion() != null) { + Map bundleManifest = (Map) bd.getUserObject(); + + if (phase == CACHE_PHASE) { + if (bundleManifest != null) { + String[] cachedValues = MetadataGeneratorHelper.getManifestCachedValues(bundleManifest); + bundleLocalizationMap.put(makeSimpleKey(bd), cachedValues); + } + } else { + IArtifactKey key = MetadataGeneratorHelper.createBundleArtifactKey(bd.getSymbolicName(), bd.getVersion().toString()); + IArtifactDescriptor ad = MetadataGeneratorHelper.createArtifactDescriptor(key, new File(bd.getLocation()), true, false); + IArtifactRepository destination = info.getArtifactRepository(); + // don't consider any advice here as we want to know about the real form on disk + if (isDir(bd, null)) + publishArtifact(ad, new File(bd.getLocation()), new File(bd.getLocation()).listFiles(), info, INCLUDE_ROOT); + else + publishArtifact(ad, new File(bd.getLocation()), new File[] {new File(bd.getLocation())}, info, AS_IS | INCLUDE_ROOT); + + boolean isDir = isDir(bd, (IBundleAdvice) info.getAdvice(IBundleAdvice.ID)); + IInstallableUnit bundleIU = MetadataGeneratorHelper.createBundleIU(bd, bundleManifest, isDir, key, localizationIUs); + + if (isFragment(bd)) { + // TODO: Can NL fragments be multi-host? What special handling + // is required for multi-host fragments in general? + String hostId = bd.getHost().getName(); + String hostKey = makeSimpleKey(hostId); + String[] cachedValues = (String[]) bundleLocalizationMap.get(hostKey); + + if (cachedValues != null) { + MetadataGeneratorHelper.createHostLocalizationFragments(bd, hostId, cachedValues, localizationIUs); + } + } + + result.addIU(bundleIU, IPublisherResult.ROOT); + result.addIUs(localizationIUs, IPublisherResult.NON_ROOT); + localizationIUs.clear(); + } + } + } + } + } + + private boolean isDir(BundleDescription bundle, IBundleAdvice advice) { + // if the advice has a shape, use it + if (advice != null) { + String shape = advice.getShape(bundle.getSymbolicName(), bundle.getVersion().toString()); + if (shape != null) + return shape.equals(IBundleAdvice.DIR); + } + // otherwise go with whatever we figured out from the manifest or the shape on disk + Map manifest = (Map) bundle.getUserObject(); + String format = (String) manifest.get(BundleDescriptionFactory.BUNDLE_SHAPE); + return BundleDescriptionFactory.DIR.equals(format); + } + + private String makeSimpleKey(BundleDescription bd) { + // TODO: can't use the bundle version in the key for the BundleLocalization + // property map since the host specification for a fragment has a + // version range, not a version. Hence, this mechanism for finding + // manifest localization property files may break under changes + // to the BundleLocalization property of a bundle. + return makeSimpleKey(bd.getSymbolicName() /*, bd.getVersion() */); + } + + private String makeSimpleKey(String id /*, Version version */) { + return id; // + '_' + version.toString(); + } + + private boolean isFragment(BundleDescription bd) { + return (bd.getHost() != null ? true : false); + } + + protected BundleDescription[] getBundleDescriptions(File[] bundleLocations) { + if (bundleLocations == null) + return new BundleDescription[0]; + boolean addSimpleConfigurator = false; + boolean scIn = false; + for (int i = 0; i < bundleLocations.length; i++) { + if (!addSimpleConfigurator) + addSimpleConfigurator = bundleLocations[i].toString().indexOf(ORG_ECLIPSE_UPDATE_CONFIGURATOR) > 0; + if (!scIn) { + scIn = bundleLocations[i].toString().indexOf(ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR) > 0; + if (scIn) + break; + } + } + if (scIn) + addSimpleConfigurator = false; + BundleDescription[] result = new BundleDescription[bundleLocations.length + (addSimpleConfigurator ? 1 : 0)]; + BundleDescriptionFactory factory = getBundleFactory(); + for (int i = 0; i < bundleLocations.length; i++) { + result[i] = factory.getBundleDescription(bundleLocations[i]); + } + if (addSimpleConfigurator) { + //Add simple configurator to the list of bundles + try { + File location = new File(FileLocator.toFileURL(Activator.getContext().getBundle().getEntry(ORG_ECLIPSE_EQUINOX_SIMPLECONFIGURATOR + ".jar")).getFile()); //$NON-NLS-1$ + result[result.length - 1] = factory.getBundleDescription(location); + } catch (IOException e) { + e.printStackTrace(); + } + } + return result; + } + + protected BundleDescriptionFactory getBundleFactory() { + return new BundleDescriptionFactory(stateObjectFactory, null); + } + } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/ConfigCUsAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/ConfigCUsAction.java index 9129bbc24..e156a45ea 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/ConfigCUsAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/ConfigCUsAction.java @@ -13,24 +13,25 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.util.*; +import java.util.Map.Entry; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; import org.eclipse.equinox.internal.provisional.frameworkadmin.BundleInfo; import org.eclipse.equinox.internal.provisional.frameworkadmin.ConfigData; import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepository; import org.eclipse.osgi.util.ManifestElement; -import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; +import org.osgi.framework.*; /** * Publish CUs for all the configuration data in the current result. * This adds config-specific CUs to capture start levels etc found in the config.ini * etc for is os, ws, arch combination seen so far. */ -public class ConfigCUsAction extends Generator implements IPublishingAction { +public class ConfigCUsAction extends AbstractPublishingAction { + + protected static final String ORG_ECLIPSE_UPDATE_CONFIGURATOR = "org.eclipse.update.configurator"; //$NON-NLS-1$ public static final int NO_INI = 0; public static final int CONFIG_INI = 1; @@ -41,33 +42,22 @@ public class ConfigCUsAction extends Generator implements IPublishingAction { int mode; public ConfigCUsAction(IPublisherInfo info, String flavor, String id, String version, int mode) { - super(createGeneratorInfo(info, flavor)); this.flavor = flavor; this.mode = mode; this.id = id; this.version = version; } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info, String flavor) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - result.setFlavor(flavor); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { // generation from remembered config.ini's // we have N platforms, generate a CU for each // TODO try and find common properties across platforms for (Iterator iterator = results.getConfigData().keySet().iterator(); iterator.hasNext();) { - String configuration = (String) iterator.next(); - ConfigData data = (ConfigData) results.getConfigData().get(configuration); + String configSpec = (String) iterator.next(); + ConfigData data = (ConfigData) results.getConfigData().get(configSpec); BundleInfo[] bundles = fillInBundles(data.getBundles(), results); - generateBundleConfigIUs(bundles, results, configuration); - publishIniIUs(data, results, configuration); + generateBundleConfigIUs(info, bundles, configSpec, results); + publishIniIUs(data, results, configSpec); } return Status.OK_STATUS; } @@ -138,4 +128,119 @@ public class ConfigCUsAction extends Generator implements IPublishingAction { IInstallableUnit cu = MetadataGeneratorHelper.createIUFragment(id, version, flavor, configuration, touchpointData); results.addIU(cu, IPublisherResult.ROOT); } + + protected String[] getConfigurationStrings(ConfigData configData) { + String configurationData = ""; //$NON-NLS-1$ + String unconfigurationData = ""; //$NON-NLS-1$ + for (Iterator iterator = configData.getFwDependentProps().entrySet().iterator(); iterator.hasNext();) { + Entry aProperty = (Entry) iterator.next(); + String key = ((String) aProperty.getKey()); + if (key.equals("osgi.frameworkClassPath") || key.equals("osgi.framework") || key.equals("osgi.bundles") || key.equals("eof")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + continue; + configurationData += "setProgramProperty(propName:" + key + ", propValue:" + ((String) aProperty.getValue()) + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + unconfigurationData += "setProgramProperty(propName:" + key + ", propValue:);"; //$NON-NLS-1$ //$NON-NLS-2$ + } + for (Iterator iterator = configData.getFwIndependentProps().entrySet().iterator(); iterator.hasNext();) { + Entry aProperty = (Entry) iterator.next(); + String key = ((String) aProperty.getKey()); + if (key.equals("osgi.frameworkClassPath") || key.equals("osgi.framework") || key.equals("osgi.bundles") || key.equals("eof")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + continue; + configurationData += "setProgramProperty(propName:" + key + ", propValue:" + ((String) aProperty.getValue()) + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + unconfigurationData += "setProgramProperty(propName:" + key + ", propValue:);"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + return new String[] {configurationData, unconfigurationData}; + } + + protected String[] getLauncherConfigStrings(final String[] jvmArgs, final String[] programArgs) { + String configurationData = ""; //$NON-NLS-1$ + String unconfigurationData = ""; //$NON-NLS-1$ + + for (int i = 0; i < jvmArgs.length; i++) { + configurationData += "addJvmArg(jvmArg:" + jvmArgs[i] + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + unconfigurationData += "removeJvmArg(jvmArg:" + jvmArgs[i] + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + for (int i = 0; i < programArgs.length; i++) { + String programArg = programArgs[i]; + if (programArg.equals("--launcher.library") || programArg.equals("-startup") || programArg.equals("-configuration")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + i++; + configurationData += "addProgramArg(programArg:" + programArg + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + unconfigurationData += "removeProgramArg(programArg:" + programArg + ");"; //$NON-NLS-1$ //$NON-NLS-2$ + } + return new String[] {configurationData, unconfigurationData}; + } + + protected void generateBundleConfigIUs(IPublisherInfo info, BundleInfo[] bundles, String configSpec, IPublisherResult result) { + if (bundles == null) + return; + + String cuIdPrefix = ""; //$NON-NLS-1$ + String filter = null; + if (configSpec != null) { + cuIdPrefix = createIdString(configSpec); + filter = createFilterSpec(configSpec); + } + + for (int i = 0; i < bundles.length; i++) { + GeneratorBundleInfo bundle = createGeneratorBundleInfo(bundles[i], result); + if (bundle == null) + continue; + + if (bundle.getSymbolicName().equals(ORG_ECLIPSE_UPDATE_CONFIGURATOR)) { + bundle.setStartLevel(BundleInfo.NO_LEVEL); + bundle.setMarkedAsStarted(false); + bundle.setSpecialConfigCommands("setProgramProperty(propName:org.eclipse.update.reconcile, propValue:false);"); //$NON-NLS-1$ + bundle.setSpecialUnconfigCommands("setProgramProperty(propName:org.eclipse.update.reconcile, propValue:);"); //$NON-NLS-1$ + } else if (bundle.getStartLevel() == BundleInfo.NO_LEVEL && !bundle.isMarkedAsStarted()) { + // this bundle does not require any particular configuration, the plug-in default IU will handle installing it + continue; + } + + IInstallableUnit cu = MetadataGeneratorHelper.createBundleConfigurationUnit(bundle.getSymbolicName(), new Version(bundle.getVersion()), false, bundle, flavor + cuIdPrefix, filter); + if (cu != null) { + // Product Query will run against the repo, make sure these CUs are in before then + IMetadataRepository metadataRepository = info.getMetadataRepository(); + if (metadataRepository != null) { + metadataRepository.addInstallableUnits(new IInstallableUnit[] {cu}); + } + result.addIU(cu, IPublisherResult.ROOT); + // String key = (product != null && product.useFeatures()) ? IPublisherResult.CONFIGURATION_CUS : bundle.getSymbolicName(); + String key = bundle.getSymbolicName(); + result.addFragment(key, cu); + } + } + } + + protected GeneratorBundleInfo createGeneratorBundleInfo(BundleInfo bundleInfo, IPublisherResult result) { + if (bundleInfo.getLocation() != null) + return new GeneratorBundleInfo(bundleInfo); + + String name = bundleInfo.getSymbolicName(); + + //easy case: do we have a matching IU? + IInstallableUnit iu = result.getIU(name, null); + if (iu != null) { + bundleInfo.setVersion(iu.getVersion().toString()); + return new GeneratorBundleInfo(bundleInfo); + } + + //harder: try id_version + int i = name.indexOf('_'); + while (i > -1) { + Version version = null; + try { + version = new Version(name.substring(i)); + bundleInfo.setSymbolicName(name.substring(0, i)); + bundleInfo.setVersion(version.toString()); + return new GeneratorBundleInfo(bundleInfo); + } catch (IllegalArgumentException e) { + // the '_' found was probably part of the symbolic id + i = name.indexOf('_', i); + } + } + + return null; + } + } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/DefaultCUsAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/DefaultCUsAction.java index 6e92bf399..bd93e6618 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/DefaultCUsAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/DefaultCUsAction.java @@ -11,27 +11,17 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; +import org.eclipse.equinox.internal.p2.publisher.*; /** * Publish IUs that install/configure the standard things like bundles, features and source bundles */ -public class DefaultCUsAction extends Generator implements IPublishingAction { +public class DefaultCUsAction extends AbstractPublishingAction { - public DefaultCUsAction(IPublisherInfo info, String flavor) { - super(createGeneratorInfo(info, flavor)); - } + private String flavor; - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info, String flavor) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - result.setFlavor(flavor); - return result; + public DefaultCUsAction(IPublisherInfo info, String flavor) { + this.flavor = flavor; } public IStatus perform(IPublisherInfo info, IPublisherResult results) { @@ -39,4 +29,34 @@ public class DefaultCUsAction extends Generator implements IPublishingAction { return Status.OK_STATUS; } + protected void generateDefaultConfigIU(IPublisherResult result) { + // TODO this is a bit of a hack. We need to have the default IU fragment generated with code that configures + // and unconfigures. The Generator should be decoupled from any particular provider but it is not clear + // that we should add the create* methods to IGeneratorInfo... + // MockBundleDescription bd1 = new MockBundleDescription("defaultConfigure"); + // MockBundleDescription bd2 = new MockBundleDescription("defaultUnconfigure"); + result.addIU(MetadataGeneratorHelper.createDefaultBundleConfigurationUnit(createDefaultConfigurationBundleInfo(), createDefaultUnconfigurationBundleInfo(), flavor), IPublisherResult.ROOT); + result.addIU(MetadataGeneratorHelper.createDefaultFeatureConfigurationUnit(flavor), IPublisherResult.ROOT); + result.addIU(MetadataGeneratorHelper.createDefaultConfigurationUnitForSourceBundles(flavor), IPublisherResult.ROOT); + } + + protected GeneratorBundleInfo createDefaultConfigurationBundleInfo() { + GeneratorBundleInfo result = new GeneratorBundleInfo(); + result.setSymbolicName("defaultConfigure"); //$NON-NLS-1$ + result.setVersion("1.0.0"); //$NON-NLS-1$ + result.setStartLevel(4); + // These should just be in the install section now + // result.setSpecialConfigCommands("installBundle(bundle:${artifact});"); + return result; + } + + protected GeneratorBundleInfo createDefaultUnconfigurationBundleInfo() { + GeneratorBundleInfo result = new GeneratorBundleInfo(); + result.setSymbolicName("defaultUnconfigure"); //$NON-NLS-1$ + result.setVersion("1.0.0"); //$NON-NLS-1$ + // These should just be in the uninstall section now + // result.setSpecialConfigCommands("uninstallBundle(bundle:${artifact});"); + return result; + } + } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EclipseInstallAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EclipseInstallAction.java index 8cae7624b..60fbc948e 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EclipseInstallAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EclipseInstallAction.java @@ -13,26 +13,24 @@ import java.io.File; import java.util.*; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.Generator; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.IPublisherResult; +import org.eclipse.equinox.internal.p2.publisher.*; public class EclipseInstallAction implements IPublishingAction { - + protected String source; protected String id; protected String version = "1.0.0"; //$NON-NLS-1$ + protected String name; protected String flavor; protected String[] topLevel; protected IPublisherInfo info; protected String[] configurations; - protected String source; protected String[] nonRootFiles; - public EclipseInstallAction(String source, String id, String version, String flavor, String[] topLevel, String[] configurations, String[] nonRootFiles) { + public EclipseInstallAction(String source, String id, String version, String name, String flavor, String[] topLevel, String[] configurations, String[] nonRootFiles) { this.source = source; this.id = id; this.version = version; + this.name = name == null ? id : name; this.flavor = flavor; this.topLevel = topLevel; this.configurations = configurations; @@ -50,7 +48,7 @@ public class EclipseInstallAction implements IPublishingAction { protected IPublishingAction[] createActions() { ArrayList result = new ArrayList(); // create an action that just publishes the raw bundles and features - IPublishingAction action = new MergeResultsAction(new IPublishingAction[] {createBundlesAction(), createFeaturesAction()}, IPublisherResult.MERGE_ALL_NON_ROOT); + IPublishingAction action = new MergeResultsAction(new IPublishingAction[] {createFeaturesAction(), createBundlesAction()}, IPublisherResult.MERGE_ALL_NON_ROOT); result.add(action); result.addAll(createEquinoxExecutableActions(configurations)); result.addAll(createRootFilesActions(configurations)); @@ -68,7 +66,7 @@ public class EclipseInstallAction implements IPublishingAction { } protected IPublishingAction createRootIUAction() { - return new RootIUAction(id, version, topLevel, info); + return new RootIUAction(id, version, name, topLevel, info); } protected IPublishingAction createJREAction() { @@ -84,8 +82,7 @@ public class EclipseInstallAction implements IPublishingAction { Collection result = new ArrayList(configs.length); for (int i = 0; i < configs.length; i++) { File configuration = computeConfigurationLocation(configs[i]); - File[] executables = computeExecutables(configs[i]); - File executable = executables[0]; + File executable = computeExecutables(configs[i])[0]; IPublishingAction action = new AccumulateConfigDataAction(info, configs[i], configuration, executable); result.add(action); } @@ -137,7 +134,7 @@ public class EclipseInstallAction implements IPublishingAction { } protected File[] computeExecutables(String configSpec) { - String os = Generator.parseConfigSpec(configSpec)[1]; + String os = AbstractPublishingAction.parseConfigSpec(configSpec)[1]; return EquinoxExecutableAction.findExecutables(computeExecutableLocation(configSpec), os, "eclipse"); } @@ -154,7 +151,7 @@ public class EclipseInstallAction implements IPublishingAction { } protected IPublishingAction createBundlesAction() { - return new BundlesAction(new File[] {new File(source, "plugins")}, info); //$NON-NLS-1$ + return new BundlesAction(new File[] {new File(source, "plugins")}); //$NON-NLS-1$ } } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxExecutableAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxExecutableAction.java index 52d32d2e3..13cf90e0b 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxExecutableAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxExecutableAction.java @@ -13,18 +13,16 @@ import java.io.File; import java.io.FilenameFilter; import java.util.*; import org.eclipse.core.runtime.*; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactDescriptor; 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.internal.provisional.p2.metadata.generator.*; import org.eclipse.osgi.service.environment.Constants; import org.eclipse.osgi.service.resolver.VersionRange; import org.osgi.framework.Version; -public class EquinoxExecutableAction extends Generator implements IPublishingAction { +public class EquinoxExecutableAction extends AbstractPublishingAction { private String configSpec; private String idBase; @@ -45,7 +43,7 @@ public class EquinoxExecutableAction extends Generator implements IPublishingAct if (!Constants.OS_WIN32.equals(os) && !Constants.OS_MACOSX.equals(os)) { ArrayList result = new ArrayList(); File[] files = root.listFiles(); - for (int i = 0; i < files.length; i++) { + 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"))) result.add(files[i]); @@ -64,7 +62,6 @@ public class EquinoxExecutableAction extends Generator implements IPublishingAct } public EquinoxExecutableAction(IPublisherInfo info, File[] executables, String configSpec, String idBase, String version, String flavor) { - super(createGeneratorInfo(info, flavor)); this.executables = executables; this.configSpec = configSpec; this.idBase = idBase == null ? "org.eclipse" : idBase; //$NON-NLS-1$ @@ -74,16 +71,6 @@ public class EquinoxExecutableAction extends Generator implements IPublishingAct this.flavor = flavor; } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info, String flavor) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - result.setFlavor(flavor); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { generateExecutableIUs(info, results); return Status.OK_STATUS; @@ -115,7 +102,7 @@ public class EquinoxExecutableAction extends Generator implements IPublishingAct String ws = config[0]; String os = config[1]; String arch = config[2]; - String launcherFragment = ORG_ECLIPSE_EQUINOX_LAUNCHER + '.' + ws + '.' + os; + String launcherFragment = EquinoxLauncherCUAction.ORG_ECLIPSE_EQUINOX_LAUNCHER + '.' + ws + '.' + os; if (!Constants.OS_MACOSX.equals(os)) launcherFragment += '.' + arch; iu.setRequiredCapabilities(new RequiredCapability[] {MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, launcherFragment, VersionRange.emptyRange, filter, false, false)}); @@ -170,7 +157,7 @@ public class EquinoxExecutableAction extends Generator implements IPublishingAct //Create the artifact descriptor. we have several files so no path on disk IArtifactDescriptor descriptor = MetadataGeneratorHelper.createArtifactDescriptor(key, null, false, true); - publishArtifact(descriptor, executables, info.getArtifactRepository(), false, true); + publishArtifact(descriptor, null, executables, info, INCLUDE_ROOT); } private void mungeLauncherFileNames(File[] files) { diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxLauncherCUAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxLauncherCUAction.java index 3946bc8d5..8d117fa8e 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxLauncherCUAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/EquinoxLauncherCUAction.java @@ -11,19 +11,16 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import java.util.*; import org.eclipse.core.runtime.IStatus; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.GeneratorBundleInfo; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.IPublisherResult; /** * Create fragments for all Equinox launcher IUs (not fragments) such that the corresponding * host IU is configured as the launch.library. */ -public class EquinoxLauncherCUAction extends FragmentIUsAction implements IPublishingAction { +public class EquinoxLauncherCUAction extends FragmentIUsAction { - private static final String ORG_ECLIPSE_EQUINOX_LAUNCHER = "org.eclipse.equinox.launcher"; //$NON-NLS-1$ + public static final String ORG_ECLIPSE_EQUINOX_LAUNCHER = "org.eclipse.equinox.launcher"; //$NON-NLS-1$ public EquinoxLauncherCUAction(IPublisherInfo info, GeneratorBundleInfo[] bundles, String flavor) { super(info, null, flavor); diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FeaturesAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FeaturesAction.java index 052b74170..7a030c126 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FeaturesAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FeaturesAction.java @@ -16,38 +16,35 @@ import org.eclipse.core.runtime.Status; 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.*; -import org.eclipse.equinox.internal.provisional.p2.artifact.repository.*; -import org.eclipse.equinox.internal.provisional.p2.metadata.IArtifactKey; -import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; +import org.eclipse.equinox.internal.p2.publisher.features.*; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.ArtifactDescriptor; +import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactDescriptor; +import org.eclipse.equinox.internal.provisional.p2.metadata.*; +import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory.InstallableUnitDescription; +import org.eclipse.osgi.service.resolver.VersionRange; +import org.osgi.framework.Version; /** * Publish IUs for all of the features in the given set of locations. The locations can * be actual locations of the features or folders of features. */ -public class FeaturesAction extends Generator implements IPublishingAction { +public class FeaturesAction extends AbstractPublishingAction { + + public static final String INSTALL_FEATURES_FILTER = "(org.eclipse.update.install.features=true)"; //$NON-NLS-1$ private File[] locations; - IPublisherInfo info; - public FeaturesAction(File[] locations, IPublisherInfo info) { - super(createGeneratorInfo(info)); - this.locations = expandLocations(locations); - this.info = info; + public static String getTransformedId(String original, boolean isPlugin, boolean isGroup) { + return (isPlugin ? original : original + (isGroup ? ".feature.group" : ".feature.jar")); //$NON-NLS-1$//$NON-NLS-2$ } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - return result; + public FeaturesAction(File[] locations, IPublisherInfo info) { + this.locations = expandLocations(locations); } public IStatus perform(IPublisherInfo info, IPublisherResult results) { Feature[] features = getFeatures(locations); - generateFeatureIUs(features, results, info.getArtifactRepository()); + generateFeatureIUs(features, results, info); return Status.OK_STATUS; } @@ -68,14 +65,14 @@ public class FeaturesAction extends Generator implements IPublishingAction { return (File[]) result.toArray(new File[result.size()]); } - protected void generateFeatureIUs(Feature[] features, IPublisherResult result, IArtifactRepository destination) { - //Build Feature IUs, and add them to any corresponding categories + protected void generateFeatureIUs(Feature[] features, IPublisherResult result, IPublisherInfo info) { + // Build Feature IUs, and add them to any corresponding categories for (int i = 0; i < features.length; i++) { Feature feature = features[i]; // generate the root file IUs for this feature. The IU hierarchy must // be built from the bottom up so do the root files first. - ArrayList childIUs = generateFeatureRootIUs(feature, result, destination); + ArrayList childIUs = generateRootFileIUs(feature, result, info); // create the basic feature IU with all the children String location = feature.getLocation(); @@ -87,21 +84,38 @@ public class FeaturesAction extends Generator implements IPublishingAction { for (int arti = 0; arti < artifacts.length; arti++) { IArtifactDescriptor ad = MetadataGeneratorHelper.createArtifactDescriptor(artifacts[arti], new File(location), true, false); if (isExploded) - publishArtifact(ad, new File(location).listFiles(), destination, false, true); + publishArtifact(ad, new File(location).listFiles(), info, INCLUDE_ROOT); else - publishArtifact(ad, new File[] {new File(location)}, destination, true, true); + publishArtifact(ad, new File[] {new File(location)}, info, AS_IS | INCLUDE_ROOT); } + gatherAdvice(feature, info); + // create the associated group and register the feature and group in the result. - IInstallableUnit generated = MetadataGeneratorHelper.createGroupIU(feature, featureIU); + IInstallableUnit generated = createGroupIU(feature, featureIU, null); result.addIU(generated, IPublisherResult.ROOT); result.addIU(featureIU, IPublisherResult.ROOT); } } - private ArrayList generateFeatureRootIUs(Feature feature, IPublisherResult result, IArtifactRepository destination) { - ArrayList ius = new ArrayList(); + private ArrayList generateRootFileIUs(Feature feature, IPublisherResult result, IPublisherInfo info) { File location = new File(feature.getLocation()); + Properties props = loadProperties(location, "build.properties"); + return generateRootFileIUs(feature.getId(), feature.getVersion(), props, location, result, info); + } + + private ArrayList generateRootFileIUs(String featureId, String featureVersion, Properties props, File location, IPublisherResult result, IPublisherInfo info) { + ArrayList ius = new ArrayList(); + FileSetDescriptor[] rootFileDescriptors = getRootFileDescriptors(props); + for (int i = 0; i < rootFileDescriptors.length; i++) { + IInstallableUnit iu = generateRootFileIU(featureId, featureVersion, location, rootFileDescriptors[i], result, info); + ius.add(iu); + } + return ius; + } + + private Properties loadProperties(File location, String file) { + Properties props = new Properties(); File tempFile = null; try { // if the feature is a dir then just return the location @@ -111,11 +125,10 @@ public class FeaturesAction extends Generator implements IPublishingAction { FileUtils.unzipFile(location, tempFile); location = tempFile; } - Properties props = new Properties(); try { InputStream in = null; try { - in = new BufferedInputStream(new FileInputStream(new File(location, "build.properties"))); //$NON-NLS-1$ + in = new BufferedInputStream(new FileInputStream(new File(location, file))); //$NON-NLS-1$ props.load(in); } finally { if (in != null) @@ -124,13 +137,7 @@ public class FeaturesAction extends Generator implements IPublishingAction { } catch (FileNotFoundException e) { // ignore if it is just a file not found. } catch (IOException e) { - LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Error parsing feature build.properties", e)); //$NON-NLS-1$ - } - - FileSetDescriptor[] rootFileDescriptors = getRootFileDescriptors(props); - for (int i = 0; i < rootFileDescriptors.length; i++) { - IInstallableUnit iu = generateFeatureRootFileIU(feature, location, rootFileDescriptors[i], result, destination); - ius.add(iu); + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Error parsing " + file, e)); //$NON-NLS-1$ } } catch (IOException e) { LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Error publishing artifacts", e)); //$NON-NLS-1$ @@ -138,17 +145,17 @@ public class FeaturesAction extends Generator implements IPublishingAction { if (tempFile != null) tempFile.delete(); } - return ius; + return props; } - private IInstallableUnit generateFeatureRootFileIU(Feature feature, File location, FileSetDescriptor rootFile, IPublisherResult result, IArtifactRepository destination) { - Object[] iuAndFiles = MetadataGeneratorHelper.createFeatureRootFileIU(feature, location, rootFile); + private IInstallableUnit generateRootFileIU(String featureId, String featureVersion, File location, FileSetDescriptor rootFile, IPublisherResult result, IPublisherInfo info) { + Object[] iuAndFiles = MetadataGeneratorHelper.createFeatureRootFileIU(featureId, featureVersion, location, rootFile); IInstallableUnit iuResult = (IInstallableUnit) iuAndFiles[0]; File[] fileResult = (File[]) iuAndFiles[1]; if (fileResult != null && fileResult.length > 0) { IArtifactKey artifact = iuResult.getArtifacts()[0]; ArtifactDescriptor descriptor = new ArtifactDescriptor(artifact); - publishArtifact(descriptor, fileResult, destination, false, false); + publishArtifact(descriptor, fileResult, info, 0); } result.addIU(iuResult, IPublisherResult.NON_ROOT); return iuResult; @@ -192,4 +199,121 @@ public class FeaturesAction extends Generator implements IPublishingAction { return (FileSetDescriptor[]) values.toArray(new FileSetDescriptor[values.size()]); } + /** + * Gather any advice we can from the given feature. In particular, it may have + * information about the shape of the bundles it includes. The discovered advice is + * added to the given result. + * @param feature the feature to process + * @param info the publishing info to update + */ + public void gatherAdvice(Feature feature, IPublisherInfo info) { + IBundleAdvice advice = (IBundleAdvice) info.getAdvice(IBundleAdvice.ID); + if (advice == null) { + advice = new BundleAdvice(); + info.setAdvice(IBundleAdvice.ID, advice); + } + FeatureEntry entries[] = feature.getEntries(); + for (int i = 0; i < entries.length; i++) { + FeatureEntry entry = entries[i]; + if (entry.isUnpack()) + advice.setShape(entry.getId(), entry.getVersion(), IBundleAdvice.DIR); + } + } + + public IInstallableUnit createGroupIU(Feature feature, IInstallableUnit featureIU, Properties extraProperties) { + InstallableUnitDescription iu = new MetadataFactory.InstallableUnitDescription(); + String id = getTransformedId(feature.getId(), /*isPlugin*/false, /*isGroup*/true); + iu.setId(id); + Version version = new Version(feature.getVersion()); + iu.setVersion(version); + iu.setProperty(IInstallableUnit.PROP_NAME, feature.getLabel()); + if (feature.getLicense() != null) + iu.setLicense(new License(feature.getLicenseURL(), feature.getLicense())); + if (feature.getCopyright() != null) + iu.setCopyright(new Copyright(feature.getCopyrightURL(), feature.getCopyright())); + iu.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(id, new VersionRange(new Version(0, 0, 0), true, new Version(feature.getVersion()), false), IUpdateDescriptor.NORMAL, null)); + + // generate requirements for the feature inclusions/requirement + FeatureEntry entries[] = feature.getEntries(); + RequiredCapability[] required = new RequiredCapability[entries.length + 1]; + for (int i = 0; i < entries.length; i++) { + VersionRange range = getVersionRange(entries[i]); + required[i] = MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, getTransformedId(entries[i].getId(), entries[i].isPlugin(), /*isGroup*/true), range, getFilter(entries[i]), entries[i].isOptional(), false); + } + required[entries.length] = MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, featureIU.getId(), new VersionRange(featureIU.getVersion(), true, featureIU.getVersion(), true), INSTALL_FEATURES_FILTER, false, false); + iu.setRequiredCapabilities(required); + iu.setTouchpointType(TouchpointType.NONE); + iu.setProperty(IInstallableUnit.PROP_TYPE_GROUP, Boolean.TRUE.toString()); + // TODO: shouldn't the filter for the group be constructed from os, ws, arch, nl + // of the feature? + // iu.setFilter(filter); + iu.setCapabilities(new ProvidedCapability[] {MetadataGeneratorHelper.createSelfCapability(id, version)}); + + if (extraProperties != null) { + Enumeration e = extraProperties.propertyNames(); + while (e.hasMoreElements()) { + String name = (String) e.nextElement(); + iu.setProperty(name, extraProperties.getProperty(name)); + } + } + return MetadataFactory.createInstallableUnit(iu); + } + + public VersionRange getVersionRange(FeatureEntry entry) { + String versionSpec = entry.getVersion(); + if (versionSpec == null) + // TODO should really be returning VersionRange.emptyRange here... + return null; + Version version = new Version(versionSpec); + if (!entry.isRequires()) + return new VersionRange(version, true, version, true); + String match = entry.getMatch(); + if (match == null) + // TODO should really be returning VersionRange.emptyRange here... + return null; + if (match.equals("perfect")) //$NON-NLS-1$ + return new VersionRange(version, true, version, true); + if (match.equals("equivalent")) { //$NON-NLS-1$ + Version upper = new Version(version.getMajor(), version.getMinor() + 1, 0); + return new VersionRange(version, true, upper, false); + } + if (match.equals("compatible")) { //$NON-NLS-1$ + Version upper = new Version(version.getMajor() + 1, 0, 0); + return new VersionRange(version, true, upper, false); + } + if (match.equals("greaterOrEqual")) //$NON-NLS-1$ + return new VersionRange(version, true, new VersionRange(null).getMaximum(), true); + return null; + } + + public String getFilter(FeatureEntry entry) { + StringBuffer result = new StringBuffer(); + result.append("(&"); //$NON-NLS-1$ + if (entry.getFilter() != null) + result.append(entry.getFilter()); + if (entry.getOS() != null) + result.append("(osgi.os=" + entry.getOS() + ')');//$NON-NLS-1$ + if (entry.getWS() != null) + result.append("(osgi.ws=" + entry.getWS() + ')');//$NON-NLS-1$ + if (entry.getArch() != null) + result.append("(osgi.arch=" + entry.getArch() + ')');//$NON-NLS-1$ + if (entry.getNL() != null) + result.append("(osgi.nl=" + entry.getNL() + ')');//$NON-NLS-1$ + if (result.length() == 2) + return null; + result.append(')'); + return result.toString(); + } + + protected Feature[] getFeatures(File[] locations) { + ArrayList result = new ArrayList(locations.length); + for (int i = 0; i < locations.length; i++) { + Feature feature = new FeatureParser().parse(locations[i]); + if (feature != null) { + feature.setLocation(locations[i].getAbsolutePath()); + result.add(feature); + } + } + return (Feature[]) result.toArray(new Feature[result.size()]); + } } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FragmentIUsAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FragmentIUsAction.java index d2a23b95c..bb9f9e508 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FragmentIUsAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/FragmentIUsAction.java @@ -11,32 +11,20 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; import org.osgi.framework.Version; -public class FragmentIUsAction extends Generator implements IPublishingAction { +public class FragmentIUsAction extends AbstractPublishingAction { protected GeneratorBundleInfo[] bundles; private String flavor; public FragmentIUsAction(IPublisherInfo info, GeneratorBundleInfo[] bundles, String flavor) { - super(createGeneratorInfo(info)); this.bundles = bundles; this.flavor = flavor; } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { for (int i = 0; i < bundles.length; i++) createFragment(bundles[i], results); diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/IBundleAdvice.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/IBundleAdvice.java new file mode 100644 index 000000000..305fc16f1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/IBundleAdvice.java @@ -0,0 +1,24 @@ +package org.eclipse.equinox.internal.p2.publisher.actions; + +import org.eclipse.equinox.internal.p2.publisher.BundleDescriptionFactory; +import org.eclipse.equinox.internal.p2.publisher.IPublishingAdvice; + +public interface IBundleAdvice extends IPublishingAdvice { + + public static final String ID = "bundle_advice"; + public static final String DIR = BundleDescriptionFactory.DIR; + public static final String JAR = BundleDescriptionFactory.JAR; + + /** + * Returns the shape (e.g., folder or JAR) of the bundle with the given name and version. + * If the version is <code>null</code> then return the advice for the most likely version + * of the bundle. + * @param id the bundle to lookup + * @param version the version of the bundle (may be <code>null</code>) + * @return the shape of the given bundle. + */ + public String getShape(String id, String version); + + public void setShape(String id, String version, String shape); + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/JREAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/JREAction.java index 7c8ae0d0a..5e69c020d 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/JREAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/JREAction.java @@ -12,32 +12,20 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import java.io.File; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactDescriptor; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; -public class JREAction extends Generator implements IPublishingAction { +public class JREAction extends AbstractPublishingAction { private File location; public JREAction(IPublisherInfo info, File location) { - super(createGeneratorInfo(info)); this.location = location; } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { IArtifactDescriptor artifact = MetadataGeneratorHelper.createJREData(location, results); - publishArtifact(artifact, new File[] {location}, info.getArtifactRepository(), false, true); + publishArtifact(artifact, null, new File[] {location}, info, INCLUDE_ROOT); return Status.OK_STATUS; } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/MergeResultsAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/MergeResultsAction.java index caab15283..fa8ccdf7e 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/MergeResultsAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/MergeResultsAction.java @@ -11,17 +11,14 @@ package org.eclipse.equinox.internal.p2.publisher.actions; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; +import org.eclipse.equinox.internal.p2.publisher.*; -public class MergeResultsAction extends Generator implements IPublishingAction { +public class MergeResultsAction extends AbstractPublishingAction { private IPublishingAction[] actions; private int mode; public MergeResultsAction(IPublishingAction[] actions, int mode) { - super(null); this.actions = actions; this.mode = mode; } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootFilesAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootFilesAction.java index 2626e696c..984c83be5 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootFilesAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootFilesAction.java @@ -1,10 +1,8 @@ -/************************************************import com.code9.ubiquity.publisher.IPublisherInfo; -import com.code9.ubiquity.publisher.IPublishingAction; -import java.io.File; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; -.eclipse.org/legal/epl-v10.html +/******************************************************************************* + * Copyright (c) 2008 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 @@ -15,17 +13,15 @@ import java.io.File; import java.util.*; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactDescriptor; 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.internal.provisional.p2.metadata.generator.*; import org.eclipse.osgi.service.resolver.VersionRange; import org.osgi.framework.Version; -public class RootFilesAction extends Generator implements IPublishingAction { +public class RootFilesAction extends AbstractPublishingAction { private String configSpec; private String idBase; @@ -35,7 +31,6 @@ public class RootFilesAction extends Generator implements IPublishingAction { private String flavor; public RootFilesAction(IPublisherInfo info, File root, File[] exclusions, String configSpec, String idBase, String version, String flavor) { - super(createGeneratorInfo(info, flavor)); this.root = root; this.exclusions = exclusions; this.configSpec = configSpec; @@ -46,16 +41,6 @@ public class RootFilesAction extends Generator implements IPublishingAction { this.flavor = flavor; } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info, String flavor) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - result.setFlavor(flavor); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { generateExecutableIUs(info, results); return Status.OK_STATUS; @@ -109,7 +94,7 @@ public class RootFilesAction extends Generator implements IPublishingAction { //Create the artifact descriptor. we have several files so no path on disk IArtifactDescriptor descriptor = MetadataGeneratorHelper.createArtifactDescriptor(key, null, false, true); - publishArtifact(descriptor, excludeFiles(root, exclusions), info.getArtifactRepository(), false, true); + publishArtifact(descriptor, null, excludeFiles(root, exclusions), info, INCLUDE_ROOT); } private File[] excludeFiles(File base, File[] exclusions) { diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootIUAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootIUAction.java index ee928125f..be36f12ce 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootIUAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/RootIUAction.java @@ -9,42 +9,33 @@ ******************************************************************************/ package org.eclipse.equinox.internal.p2.publisher.actions; -import java.util.Collection; +import java.util.*; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; -import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.MetadataFactory; +import org.eclipse.equinox.internal.p2.publisher.*; +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.generator.*; +import org.eclipse.osgi.service.resolver.VersionRange; +import org.osgi.framework.Version; /** * Create a top level IU that lists all the current roots as well as any explicitly identified * top level IUs. */ -public class RootIUAction extends Generator implements IPublishingAction { +public class RootIUAction extends AbstractPublishingAction { private String version; private String id; private String[] topLevel; + private String name; - public RootIUAction(String id, String version, String[] topLevel, IPublisherInfo info) { - super(createGeneratorInfo(info)); + public RootIUAction(String id, String version, String name, String[] topLevel, IPublisherInfo info) { this.id = id; this.version = version; + this.name = name; this.topLevel = topLevel; } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { generateRootIU(results); return Status.OK_STATUS; @@ -58,13 +49,41 @@ public class RootIUAction extends Generator implements IPublishingAction { if (iu != null) children.add(iu); } - InstallableUnitDescription descriptor = createTopLevelIUDescription(children, id, version, /* name */id, null, false); + InstallableUnitDescription descriptor = createTopLevelIUDescription(children, id, version, name, null, false); IInstallableUnit rootIU = MetadataFactory.createInstallableUnit(descriptor); if (rootIU == null) return; result.addIU(rootIU, IPublisherResult.NON_ROOT); // TODO why do we create a category here? - result.addIU(generateDefaultCategory(rootIU, rootCategory), IPublisherResult.NON_ROOT); + // result.addIU(generateDefaultCategory(rootIU, rootCategory), IPublisherResult.NON_ROOT); + } + + protected InstallableUnitDescription createTopLevelIUDescription(Collection children, String id, String version, String name, Collection requires, boolean configureLauncherData) { + InstallableUnitDescription root = new MetadataFactory.InstallableUnitDescription(); + root.setSingleton(true); + root.setId(id); + root.setVersion(new Version(version)); + root.setProperty(IInstallableUnit.PROP_NAME, name); + + ArrayList requiredCapabilities = new ArrayList(children.size()); + for (Iterator iterator = children.iterator(); iterator.hasNext();) { + IInstallableUnit iu = (IInstallableUnit) iterator.next(); + VersionRange range = new VersionRange(iu.getVersion(), true, iu.getVersion(), true); + // boolean isOptional = checkOptionalRootDependency(iu); + requiredCapabilities.add(MetadataFactory.createRequiredCapability(IInstallableUnit.NAMESPACE_IU_ID, iu.getId(), range, iu.getFilter(), false, false)); + } + if (requires != null) + requiredCapabilities.addAll(requires); + root.setRequiredCapabilities((RequiredCapability[]) requiredCapabilities.toArray(new RequiredCapability[requiredCapabilities.size()])); + root.setArtifacts(new IArtifactKey[0]); + + root.setProperty("lineUp", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + root.setUpdateDescriptor(MetadataFactory.createUpdateDescriptor(id, VersionRange.emptyRange, IUpdateDescriptor.NORMAL, null)); + root.setProperty(IInstallableUnit.PROP_TYPE_GROUP, Boolean.TRUE.toString()); + root.setCapabilities(new ProvidedCapability[] {MetadataGeneratorHelper.createSelfCapability(id, new Version(version))}); + root.setTouchpointType(MetadataGeneratorHelper.TOUCHPOINT_OSGI); + return root; } + } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/UpdateSiteAction.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/UpdateSiteAction.java index 5c305bc00..5c452e5d0 100644 --- a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/UpdateSiteAction.java +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/actions/UpdateSiteAction.java @@ -15,18 +15,15 @@ import java.util.*; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; -import org.eclipse.equinox.internal.p2.metadata.generator.Activator; -import org.eclipse.equinox.internal.p2.metadata.generator.Messages; -import org.eclipse.equinox.internal.p2.metadata.generator.features.*; -import org.eclipse.equinox.internal.p2.publisher.IPublisherInfo; -import org.eclipse.equinox.internal.p2.publisher.IPublishingAction; +import org.eclipse.equinox.internal.p2.publisher.*; +import org.eclipse.equinox.internal.p2.publisher.Messages; +import org.eclipse.equinox.internal.p2.publisher.features.*; import org.eclipse.equinox.internal.provisional.p2.core.repository.IRepository; import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit; -import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*; import org.eclipse.osgi.util.NLS; import org.osgi.framework.Version; -public class UpdateSiteAction extends Generator implements IPublishingAction { +public class UpdateSiteAction extends AbstractPublishingAction { private URL location; private IPublisherInfo info; @@ -34,7 +31,6 @@ public class UpdateSiteAction extends Generator implements IPublishingAction { private HashSet defaultCategorySet; public UpdateSiteAction(URL location, IPublisherInfo info) { - super(createGeneratorInfo(info)); this.location = location; this.info = info; initialize(); @@ -49,15 +45,6 @@ public class UpdateSiteAction extends Generator implements IPublishingAction { defaultCategorySet.add(defaultCategory); } - private static IGeneratorInfo createGeneratorInfo(IPublisherInfo info) { - EclipseInstallGeneratorInfoProvider result = new EclipseInstallGeneratorInfoProvider(); - result.setArtifactRepository(info.getArtifactRepository()); - result.setMetadataRepository(info.getMetadataRepository()); - result.setPublishArtifactRepository(info.publishArtifactRepository()); - result.setPublishArtifacts(info.publishArtifacts()); - return result; - } - public IStatus perform(IPublisherInfo info, IPublisherResult results) { generateCategories(results); return Status.OK_STATUS; @@ -145,4 +132,16 @@ public class UpdateSiteAction extends Generator implements IPublishingAction { } return mappings; } + + /** + * Generates IUs corresponding to update site categories. + * @param categoriesToFeatures Map of SiteCategory ->Set (Feature IUs in that category). + * @param result The generator result being built + */ + protected void generateCategoryIUs(Map categoriesToFeatures, IPublisherResult result) { + for (Iterator it = categoriesToFeatures.keySet().iterator(); it.hasNext();) { + SiteCategory category = (SiteCategory) it.next(); + result.addIU(MetadataGeneratorHelper.createCategoryIU(category, (Set) categoriesToFeatures.get(category), null), IPublisherResult.NON_ROOT); + } + } } diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/DefaultSiteParser.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/DefaultSiteParser.java new file mode 100644 index 000000000..fa99d90fe --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/DefaultSiteParser.java @@ -0,0 +1,850 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.io.*; +import java.util.*; +import javax.xml.parsers.*; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.internal.p2.core.helpers.Tracing; +import org.eclipse.equinox.internal.p2.metadata.repository.Activator; +import org.eclipse.osgi.util.NLS; +import org.w3c.dom.*; +import org.xml.sax.*; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Parses a site.xml file. + * This class was initially copied from org.eclipse.update.core.model.DefaultSiteParser. + */ +public class DefaultSiteParser extends DefaultHandler { + + private static final String ARCHIVE = "archive"; //$NON-NLS-1$ + private static final String CATEGORY = "category"; //$NON-NLS-1$ + private static final String CATEGORY_DEF = "category-def"; //$NON-NLS-1$ + + //private static final String ASSOCIATE_SITES = "associateSites"; //$NON-NLS-1$ + // private static final String ASSOCIATE_SITE = "associateSite"; //$NON-NLS-1$ + private static final String DEFAULT_INFO_URL = "index.html"; //$NON-NLS-1$ + private static final String DESCRIPTION = "description"; //$NON-NLS-1$ + private static final String FEATURE = "feature"; //$NON-NLS-1$ + private static final String FEATURES = "features/"; //$NON-NLS-1$ + private static final String MIRROR = "mirror"; //$NON-NLS-1$ + private final static SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + private static final String PLUGIN_ID = Activator.ID; + private static final String SITE = "site"; //$NON-NLS-1$ + + private static final int STATE_ARCHIVE = 3; + private static final int STATE_CATEGORY = 4; + private static final int STATE_CATEGORY_DEF = 5; + private static final int STATE_DESCRIPTION_CATEGORY_DEF = 7; + private static final int STATE_DESCRIPTION_SITE = 6; + private static final int STATE_FEATURE = 2; + private static final int STATE_IGNORED_ELEMENT = -1; + private static final int STATE_INITIAL = 0; + private static final int STATE_SITE = 1; + + private int currentState; + + private boolean DESCRIPTION_SITE_ALREADY_SEEN = false; + // Current object stack (used to hold the current object we are + // populating in this plugin descriptor + Stack objectStack = new Stack(); + + private SAXParser parser; + + // Current State Information + Stack stateStack = new Stack(); + + private MultiStatus status; + + /* + * + */ + private static void debug(String s) { + Tracing.debug("DefaultSiteParser: " + s); //$NON-NLS-1$ + } + + // private static URLEntry[] getAssociateSites(String associateSitesURL) { + // + // try { + // DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); + // DocumentBuilder builder = domFactory.newDocumentBuilder(); + // Document document = builder.parse(associateSitesURL); + // if (document == null) + // return null; + // NodeList mirrorNodes = document.getElementsByTagName(ASSOCIATE_SITE); + // URLEntry[] mirrors = new URLEntry[mirrorNodes.getLength()]; + // for (int i = 0; i < mirrorNodes.getLength(); i++) { + // Element mirrorNode = (Element) mirrorNodes.item(i); + // mirrors[i] = new URLEntry(); + // String infoURL = mirrorNode.getAttribute("url"); //$NON-NLS-1$ + // String label = mirrorNode.getAttribute("label"); //$NON-NLS-1$ + // mirrors[i].setURL(infoURL); + // mirrors[i].setAnnotation(label); + // + // if (Tracing.DEBUG_GENERATOR_PARSING) + // debug("Processed mirror: url:" + infoURL + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$ + // } + // return mirrors; + // } catch (Exception e) { + // // log if absolute url + // if (associateSitesURL != null && (associateSitesURL.startsWith("http://") //$NON-NLS-1$ + // || associateSitesURL.startsWith("https://") //$NON-NLS-1$ + // || associateSitesURL.startsWith("file://") //$NON-NLS-1$ + // || associateSitesURL.startsWith("ftp://") //$NON-NLS-1$ + // || associateSitesURL.startsWith("jar://"))) //$NON-NLS-1$ + // log(Messages.DefaultSiteParser_mirrors, e); + // return null; + // } + // } + + static URLEntry[] getMirrors(String mirrorsURL) { + + try { + String countryCode = Locale.getDefault().getCountry().toLowerCase(); + int timeZone = (new GregorianCalendar()).get(Calendar.ZONE_OFFSET) / (60 * 60 * 1000); + + if (mirrorsURL.indexOf("?") != -1) { //$NON-NLS-1$ + mirrorsURL = mirrorsURL + "&"; //$NON-NLS-1$ + } else { + mirrorsURL = mirrorsURL + "?"; //$NON-NLS-1$ + } + mirrorsURL = mirrorsURL + "countryCode=" + countryCode + "&timeZone=" + timeZone + "&responseType=xml"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = domFactory.newDocumentBuilder(); + Document document = builder.parse(mirrorsURL); + if (document == null) + return null; + NodeList mirrorNodes = document.getElementsByTagName(MIRROR); + URLEntry[] mirrors = new URLEntry[mirrorNodes.getLength()]; + for (int i = 0; i < mirrorNodes.getLength(); i++) { + Element mirrorNode = (Element) mirrorNodes.item(i); + mirrors[i] = new URLEntry(); + String infoURL = mirrorNode.getAttribute("url"); //$NON-NLS-1$ + String label = mirrorNode.getAttribute("label"); //$NON-NLS-1$ + mirrors[i].setURL(infoURL); + mirrors[i].setAnnotation(label); + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("Processed mirror: url:" + infoURL + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$ + } + return mirrors; + } catch (Exception e) { + // log if absolute url + if (mirrorsURL != null && (mirrorsURL.startsWith("http://") //$NON-NLS-1$ + || mirrorsURL.startsWith("https://") //$NON-NLS-1$ + || mirrorsURL.startsWith("file://") //$NON-NLS-1$ + || mirrorsURL.startsWith("ftp://") //$NON-NLS-1$ + || mirrorsURL.startsWith("jar://"))) //$NON-NLS-1$ + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, Messages.DefaultSiteParser_mirrors, e)); + return null; + } + } + + static void log(Exception e) { + LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Internal Error", e)); //$NON-NLS-1$ + } + + static void log(IStatus error) { + LogHelper.log(error); + } + + static void log(String message) { + LogHelper.log(new Status(IStatus.WARNING, Activator.ID, message, null)); + } + + static void log(String message, Exception e) { + LogHelper.log(new Status(IStatus.WARNING, Activator.ID, message, e)); + } + + /** + * Constructs a site parser. + */ + public DefaultSiteParser() { + super(); + stateStack = new Stack(); + objectStack = new Stack(); + status = null; + DESCRIPTION_SITE_ALREADY_SEEN = false; + try { + parserFactory.setNamespaceAware(true); + this.parser = parserFactory.newSAXParser(); + } catch (ParserConfigurationException e) { + log(e); + } catch (SAXException e) { + log(e); + } + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("Created"); //$NON-NLS-1$ + } + + /** + * Handle character text + * @see DefaultHandler#characters(char[], int, int) + * @since 2.0 + */ + public void characters(char[] ch, int start, int length) { + String text = new String(ch, start, length); + //only push if description + int state = ((Integer) stateStack.peek()).intValue(); + if (state == STATE_DESCRIPTION_SITE || state == STATE_DESCRIPTION_CATEGORY_DEF) + objectStack.push(text); + + } + + /** + * Handle end of element tags + * @see DefaultHandler#endElement(String, String, String) + * @since 2.0 + */ + public void endElement(String uri, String localName, String qName) { + + String text = null; + URLEntry info = null; + + int state = ((Integer) stateStack.peek()).intValue(); + switch (state) { + case STATE_IGNORED_ELEMENT : + case STATE_ARCHIVE : + case STATE_CATEGORY : + stateStack.pop(); + break; + + case STATE_INITIAL : + internalError(Messages.DefaultSiteParser_ParsingStackBackToInitialState); + break; + + case STATE_SITE : + stateStack.pop(); + if (objectStack.peek() instanceof String) { + text = (String) objectStack.pop(); + SiteModel site = (SiteModel) objectStack.peek(); + site.getDescription().setAnnotation(text); + } + //do not pop the object + break; + + case STATE_FEATURE : + stateStack.pop(); + objectStack.pop(); + break; + + case STATE_CATEGORY_DEF : + stateStack.pop(); + if (objectStack.peek() instanceof String) { + text = (String) objectStack.pop(); + SiteCategory category = (SiteCategory) objectStack.peek(); + category.setDescription(text); + } + objectStack.pop(); + break; + + case STATE_DESCRIPTION_SITE : + stateStack.pop(); + text = ""; //$NON-NLS-1$ + while (objectStack.peek() instanceof String) { + // add text, preserving at most one space between text fragments + String newText = (String) objectStack.pop(); + if (trailingSpace(newText) && !leadingSpace(text)) { + text = " " + text; //$NON-NLS-1$ + } + text = newText.trim() + text; + if (leadingSpace(newText) && !leadingSpace(text)) { + text = " " + text; //$NON-NLS-1$ + } + } + text = text.trim(); + + info = (URLEntry) objectStack.pop(); + if (text != null) + info.setAnnotation(text); + + SiteModel siteModel = (SiteModel) objectStack.peek(); + // override description. + // do not raise error as previous description may be default one + // when parsing site tag + if (DESCRIPTION_SITE_ALREADY_SEEN) + debug(NLS.bind(Messages.DefaultSiteParser_ElementAlreadySet, (new String[] {getState(state)}))); + siteModel.setDescription(info); + DESCRIPTION_SITE_ALREADY_SEEN = true; + break; + + case STATE_DESCRIPTION_CATEGORY_DEF : + stateStack.pop(); + text = ""; //$NON-NLS-1$ + while (objectStack.peek() instanceof String) { + // add text, preserving at most one space between text fragments + String newText = (String) objectStack.pop(); + if (trailingSpace(newText) && !leadingSpace(text)) { + text = " " + text; //$NON-NLS-1$ + } + text = newText.trim() + text; + if (leadingSpace(newText) && !leadingSpace(text)) { + text = " " + text; //$NON-NLS-1$ + } + } + text = text.trim(); + + info = (URLEntry) objectStack.pop(); + if (text != null) + info.setAnnotation(text); + + SiteCategory category = (SiteCategory) objectStack.peek(); + if (category.getDescription() != null) + internalError(NLS.bind(Messages.DefaultSiteParser_ElementAlreadySet, (new String[] {getState(state), category.getLabel()}))); + else + category.setDescription(info.getAnnotation()); + break; + + default : + internalError(NLS.bind(Messages.DefaultSiteParser_UnknownEndState, (new String[] {getState(state)}))); + break; + } + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("End Element:" + uri + ":" + localName + ":" + qName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /* + * Handles an error state specified by the status. The collection of all logged status + * objects can be accessed using <code>getStatus()</code>. + * + * @param error a status detailing the error condition + */ + private void error(IStatus error) { + + if (status == null) { + status = new MultiStatus(PLUGIN_ID, 0, Messages.DefaultSiteParser_ErrorParsingSite, null); + } + + status.add(error); + if (Tracing.DEBUG_GENERATOR_PARSING) + LogHelper.log(error); + } + + /** + * Handle errors + * @see DefaultHandler#error(SAXParseException) + * @since 2.0 + */ + public void error(SAXParseException ex) { + logStatus(ex); + } + + /** + * Handle fatal errors + * @see DefaultHandler#fatalError(SAXParseException) + * @exception SAXException + * @since 2.0 + */ + public void fatalError(SAXParseException ex) throws SAXException { + logStatus(ex); + throw ex; + } + + /* + * return the state as String + */ + private String getState(int state) { + + switch (state) { + case STATE_IGNORED_ELEMENT : + return "Ignored"; //$NON-NLS-1$ + + case STATE_INITIAL : + return "Initial"; //$NON-NLS-1$ + + case STATE_SITE : + return "Site"; //$NON-NLS-1$ + + case STATE_FEATURE : + return "Feature"; //$NON-NLS-1$ + + case STATE_ARCHIVE : + return "Archive"; //$NON-NLS-1$ + + case STATE_CATEGORY : + return "Category"; //$NON-NLS-1$ + + case STATE_CATEGORY_DEF : + return "Category Def"; //$NON-NLS-1$ + + case STATE_DESCRIPTION_CATEGORY_DEF : + return "Description / Category Def"; //$NON-NLS-1$ + + case STATE_DESCRIPTION_SITE : + return "Description / Site"; //$NON-NLS-1$ + + default : + return Messages.DefaultSiteParser_UnknownState; + } + } + + /** + * Returns all status objects accumulated by the parser. + * + * @return multi-status containing accumulated status, or <code>null</code>. + * @since 2.0 + */ + public MultiStatus getStatus() { + return status; + } + + private void handleCategoryDefState(String elementName, Attributes attributes) { + if (elementName.equals(FEATURE)) { + stateStack.push(new Integer(STATE_FEATURE)); + processFeature(attributes); + } else if (elementName.equals(ARCHIVE)) { + stateStack.push(new Integer(STATE_ARCHIVE)); + processArchive(attributes); + } else if (elementName.equals(CATEGORY_DEF)) { + stateStack.push(new Integer(STATE_CATEGORY_DEF)); + processCategoryDef(attributes); + } else if (elementName.equals(DESCRIPTION)) { + stateStack.push(new Integer(STATE_DESCRIPTION_CATEGORY_DEF)); + processInfo(attributes); + } else + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)}))); + } + + private void handleCategoryState(String elementName, Attributes attributes) { + if (elementName.equals(DESCRIPTION)) { + stateStack.push(new Integer(STATE_DESCRIPTION_SITE)); + processInfo(attributes); + } else if (elementName.equals(FEATURE)) { + stateStack.push(new Integer(STATE_FEATURE)); + processFeature(attributes); + } else if (elementName.equals(ARCHIVE)) { + stateStack.push(new Integer(STATE_ARCHIVE)); + processArchive(attributes); + } else if (elementName.equals(CATEGORY_DEF)) { + stateStack.push(new Integer(STATE_CATEGORY_DEF)); + processCategoryDef(attributes); + } else if (elementName.equals(CATEGORY)) { + stateStack.push(new Integer(STATE_CATEGORY)); + processCategory(attributes); + } else + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)}))); + } + + private void handleFeatureState(String elementName, Attributes attributes) { + if (elementName.equals(DESCRIPTION)) { + stateStack.push(new Integer(STATE_DESCRIPTION_SITE)); + processInfo(attributes); + } else if (elementName.equals(FEATURE)) { + stateStack.push(new Integer(STATE_FEATURE)); + processFeature(attributes); + } else if (elementName.equals(ARCHIVE)) { + stateStack.push(new Integer(STATE_ARCHIVE)); + processArchive(attributes); + } else if (elementName.equals(CATEGORY_DEF)) { + stateStack.push(new Integer(STATE_CATEGORY_DEF)); + processCategoryDef(attributes); + } else if (elementName.equals(CATEGORY)) { + stateStack.push(new Integer(STATE_CATEGORY)); + processCategory(attributes); + } else + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)}))); + } + + private void handleInitialState(String elementName, Attributes attributes) throws SAXException { + if (elementName.equals(SITE)) { + stateStack.push(new Integer(STATE_SITE)); + processSite(attributes); + } else { + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)}))); + // what we received was not a site.xml, no need to continue + throw new SAXException(Messages.DefaultSiteParser_InvalidXMLStream); + } + + } + + private void handleSiteState(String elementName, Attributes attributes) { + if (elementName.equals(DESCRIPTION)) { + stateStack.push(new Integer(STATE_DESCRIPTION_SITE)); + processInfo(attributes); + } else if (elementName.equals(FEATURE)) { + stateStack.push(new Integer(STATE_FEATURE)); + processFeature(attributes); + } else if (elementName.equals(ARCHIVE)) { + stateStack.push(new Integer(STATE_ARCHIVE)); + processArchive(attributes); + } else if (elementName.equals(CATEGORY_DEF)) { + stateStack.push(new Integer(STATE_CATEGORY_DEF)); + processCategoryDef(attributes); + } else + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)}))); + } + + /* + * + */ + private void internalError(String message) { + error(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, message, null)); + } + + /* + * + */ + private void internalErrorUnknownTag(String msg) { + stateStack.push(new Integer(STATE_IGNORED_ELEMENT)); + internalError(msg); + } + + private boolean leadingSpace(String str) { + if (str.length() <= 0) { + return false; + } + return Character.isWhitespace(str.charAt(0)); + } + + /* + * + */ + private void logStatus(SAXParseException ex) { + String name = ex.getSystemId(); + if (name == null) + name = ""; //$NON-NLS-1$ + else + name = name.substring(1 + name.lastIndexOf("/")); //$NON-NLS-1$ + + String msg; + if (name.equals("")) //$NON-NLS-1$ + msg = NLS.bind(Messages.DefaultSiteParser_ErrorParsing, (new String[] {ex.getMessage()})); + else { + String[] values = new String[] {name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()}; + msg = NLS.bind(Messages.DefaultSiteParser_ErrorlineColumnMessage, values); + } + error(new Status(IStatus.ERROR, PLUGIN_ID, msg, ex)); + } + + /** + * Parses the specified input steam and constructs a site model. + * The input stream is not closed as part of this operation. + * + * @param in input stream + * @return site model + * @exception SAXException + * @exception IOException + * @since 2.0 + */ + public SiteModel parse(InputStream in) throws SAXException, IOException { + stateStack.push(new Integer(STATE_INITIAL)); + currentState = ((Integer) stateStack.peek()).intValue(); + parser.parse(new InputSource(in), this); + if (objectStack.isEmpty()) + throw new SAXException(Messages.DefaultSiteParser_NoSiteTag); + if (objectStack.peek() instanceof SiteModel) { + return (SiteModel) objectStack.pop(); + } + String stack = ""; //$NON-NLS-1$ + Iterator iter = objectStack.iterator(); + while (iter.hasNext()) { + stack = stack + iter.next().toString() + "\r\n"; //$NON-NLS-1$ + } + throw new SAXException(NLS.bind(Messages.DefaultSiteParser_WrongParsingStack, (new String[] {stack}))); + } + + /* + * process archive info + */ + private void processArchive(Attributes attributes) { + URLEntry archive = new URLEntry(); + String id = attributes.getValue("path"); //$NON-NLS-1$ + if (id == null || id.trim().equals("")) { //$NON-NLS-1$ + internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"path", getState(currentState)}))); //$NON-NLS-1$ + } + + archive.setAnnotation(id); + + String url = attributes.getValue("url"); //$NON-NLS-1$ + if (url == null || url.trim().equals("")) { //$NON-NLS-1$ + internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"archive", getState(currentState)}))); //$NON-NLS-1$ + } else { + archive.setURL(url); + + SiteModel site = (SiteModel) objectStack.peek(); + site.addArchive(archive); + } + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("End processing Archive: path:" + id + " url:" + url);//$NON-NLS-1$ //$NON-NLS-2$ + + } + + /* + * process the Category info + */ + private void processCategory(Attributes attributes) { + String category = attributes.getValue("name"); //$NON-NLS-1$ + SiteFeature feature = (SiteFeature) objectStack.peek(); + feature.addCategoryName(category); + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("End processing Category: name:" + category); //$NON-NLS-1$ + } + + /* + * process category def info + */ + private void processCategoryDef(Attributes attributes) { + SiteCategory category = new SiteCategory(); + String name = attributes.getValue("name"); //$NON-NLS-1$ + String label = attributes.getValue("label"); //$NON-NLS-1$ + category.setName(name); + category.setLabel(label); + + SiteModel site = (SiteModel) objectStack.peek(); + site.addCategory(category); + objectStack.push(category); + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("End processing CategoryDef: name:" + name + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /* + * process feature info + */ + private void processFeature(Attributes attributes) { + SiteFeature feature = new SiteFeature(); + + // feature location on the site + String urlInfo = attributes.getValue("url"); //$NON-NLS-1$ + // identifier and version + String id = attributes.getValue("id"); //$NON-NLS-1$ + String ver = attributes.getValue("version"); //$NON-NLS-1$ + + boolean noURL = (urlInfo == null || urlInfo.trim().equals("")); //$NON-NLS-1$ + boolean noId = (id == null || id.trim().equals("")); //$NON-NLS-1$ + boolean noVersion = (ver == null || ver.trim().equals("")); //$NON-NLS-1$ + + // We need to have id and version, or the url, or both. + if (noURL) { + if (noId || noVersion) + internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"url", getState(currentState)}))); //$NON-NLS-1$ + else + // default url + urlInfo = FEATURES + id + '_' + ver; // + } + + feature.setURLString(urlInfo); + + String type = attributes.getValue("type"); //$NON-NLS-1$ + feature.setType(type); + + // if one is null, and not the other + if (noId ^ noVersion) { + String[] values = new String[] {id, ver, getState(currentState)}; + log(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, values)); + } else { + feature.setFeatureIdentifier(id); + feature.setFeatureVersion(ver); + } + + // get label if it exists + String label = attributes.getValue("label"); //$NON-NLS-1$ + if (label != null) { + if ("".equals(label.trim())) //$NON-NLS-1$ + label = null; + } + feature.setLabel(label); + + // OS + String os = attributes.getValue("os"); //$NON-NLS-1$ + feature.setOS(os); + + // WS + String ws = attributes.getValue("ws"); //$NON-NLS-1$ + feature.setWS(ws); + + // NL + String nl = attributes.getValue("nl"); //$NON-NLS-1$ + feature.setNL(nl); + + // arch + String arch = attributes.getValue("arch"); //$NON-NLS-1$ + feature.setArch(arch); + + //patch + String patch = attributes.getValue("patch"); //$NON-NLS-1$ + feature.setPatch(patch); + + SiteModel site = (SiteModel) objectStack.peek(); + site.addFeature(feature); + feature.setSiteModel(site); + + objectStack.push(feature); + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("End Processing DefaultFeature Tag: url:" + urlInfo + " type:" + type); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + /* + * process URL info with element text + */ + private void processInfo(Attributes attributes) { + URLEntry inf = new URLEntry(); + String infoURL = attributes.getValue("url"); //$NON-NLS-1$ + inf.setURL(infoURL); + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("Processed Info: url:" + infoURL); //$NON-NLS-1$ + + objectStack.push(inf); + } + + /* + * process site info + */ + private void processSite(Attributes attributes) { + // create site map + SiteModel site = new SiteModel(); + + // if URL is specified, it replaces the URL of the site + // used to calculate the location of features and archives + String siteURL = attributes.getValue("url"); //$NON-NLS-1$ + if (siteURL != null && !("".equals(siteURL.trim()))) { //$NON-NLS-1$ + if (!siteURL.endsWith("/") && !siteURL.endsWith(File.separator)) { //$NON-NLS-1$ + siteURL += "/"; //$NON-NLS-1$ + } + site.setLocationURLString(siteURL); + } + + // provide default description URL + // If <description> is specified, for the site, it takes precedence + URLEntry description = new URLEntry(); + description.setURL(DEFAULT_INFO_URL); + site.setDescription(description); + + // verify we can parse the site ...if the site has + // a different type throw an exception to force reparsing + // with the matching parser + String type = attributes.getValue("type"); //$NON-NLS-1$ + site.setType(type); + + // get mirrors, if any + String mirrorsURL = attributes.getValue("mirrorsURL"); //$NON-NLS-1$ + if (mirrorsURL != null && mirrorsURL.trim().length() > 0) { + // URLEntry[] mirrors = getMirrors(mirrorsURL); + // if (mirrors != null) + // site.setMirrors(mirrors); + // else + + //Since we are parsing the site at p2 generation time and the + //mirrors may change, there is no point doing the mirror expansion now + site.setMirrorsURLString(mirrorsURL); + } + + String pack200 = attributes.getValue("pack200"); //$NON-NLS-1$ + if (pack200 != null && new Boolean(pack200).booleanValue()) { + site.setSupportsPack200(true); + } + + // if (attributes.getValue("digestURL") != null) { //$NON-NLS-1$ + // site.setDigestExist(true); + // site.setDigestURL(attributes.getValue("digestURL")); //$NON-NLS-1$ + // + // if ((attributes.getValue("availableLocales") != null) && (!attributes.getValue("availableLocales").trim().equals(""))) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + // StringTokenizer locals = new StringTokenizer(attributes.getValue("availableLocales"), ","); //$NON-NLS-1$//$NON-NLS-2$ + // String[] availableLocals = new String[locals.countTokens()]; + // int i = 0; + // while (locals.hasMoreTokens()) { + // availableLocals[i++] = locals.nextToken(); + // } + // extendedSite.setAvailableLocals(availableLocals); + // } + // } + // + // if ((site instanceof ExtendedSite) && (attributes.getValue("associateSitesURL") != null)) { //$NON-NLS-1$ + // IURLEntry[] associateSites = getAssociateSites(attributes.getValue("associateSitesURL"), factory); //$NON-NLS-1$ + // if (associateSites != null) + // ((ExtendedSite) site).setAssociateSites(associateSites); + // else + // site.setMirrorsURLString(mirrorsURL); + // } + + objectStack.push(site); + + if (Tracing.DEBUG_GENERATOR_PARSING) + debug("End process Site tag: siteURL:" + siteURL + " type:" + type);//$NON-NLS-1$ //$NON-NLS-2$ + + } + + /** + * Handle start of element tags + * @see DefaultHandler#startElement(String, String, String, Attributes) + * @since 2.0 + */ + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + + if (Tracing.DEBUG_GENERATOR_PARSING) { + debug("State: " + currentState); //$NON-NLS-1$ + debug("Start Element: uri:" + uri + " local Name:" + localName + " qName:" + qName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + switch (currentState) { + case STATE_IGNORED_ELEMENT : + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {localName, getState(currentState)}))); + break; + case STATE_INITIAL : + handleInitialState(localName, attributes); + break; + + case STATE_SITE : + handleSiteState(localName, attributes); + break; + + case STATE_FEATURE : + handleFeatureState(localName, attributes); + break; + + case STATE_ARCHIVE : + handleSiteState(localName, attributes); + break; + + case STATE_CATEGORY : + handleCategoryState(localName, attributes); + break; + + case STATE_CATEGORY_DEF : + handleCategoryDefState(localName, attributes); + break; + + case STATE_DESCRIPTION_SITE : + handleSiteState(localName, attributes); + break; + + case STATE_DESCRIPTION_CATEGORY_DEF : + handleSiteState(localName, attributes); + break; + + default : + internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownStartState, (new String[] {getState(currentState)}))); + break; + } + int newState = ((Integer) stateStack.peek()).intValue(); + if (newState != STATE_IGNORED_ELEMENT) + currentState = newState; + + } + + private boolean trailingSpace(String str) { + if (str.length() <= 0) { + return false; + } + return Character.isWhitespace(str.charAt(str.length() - 1)); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/DigestParser.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/DigestParser.java new file mode 100644 index 000000000..bd7062624 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/DigestParser.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import javax.xml.parsers.*; +import org.xml.sax.*; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Default feature parser. + * Parses the feature manifest file as defined by the platform. + * + * @since 3.0 + */ +public class DigestParser extends DefaultHandler { + + private final static SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + private SAXParser parser; + private final List features = new ArrayList(); + private final FeatureParser featureHandler = new FeatureParser(false); + + public DigestParser() { + super(); + try { + parserFactory.setNamespaceAware(true); + this.parser = parserFactory.newSAXParser(); + } catch (ParserConfigurationException e) { + System.out.println(e); + } catch (SAXException e) { + System.out.println(e); + } + } + + public void characters(char[] ch, int start, int length) throws SAXException { + featureHandler.characters(ch, start, length); + } + + public void endElement(String uri, String localName, String qName) throws SAXException { + if ("digest".equals(localName)) { //$NON-NLS-1$ + return; + } + if ("feature".equals(localName)) { //$NON-NLS-1$ + Feature feature = featureHandler.getResult(); + features.add(feature); + } else + featureHandler.endElement(uri, localName, qName); + } + + public Feature[] parse(File location) { + if (!location.exists()) + return null; + + InputStream is = null; + try { + JarFile jar = new JarFile(location); + JarEntry entry = jar.getJarEntry("digest.xml"); //$NON-NLS-1$ + if (entry == null) + return null; + is = new BufferedInputStream(jar.getInputStream(entry)); + parser.parse(new InputSource(is), this); + return (Feature[]) features.toArray(new Feature[features.size()]); + } catch (IOException e) { + e.printStackTrace(); + } catch (SAXException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e1) { + // + } + } + return null; + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if ("digest".equals(localName)) { //$NON-NLS-1$ + return; + } + featureHandler.startElement(uri, localName, qName, attributes); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/Feature.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/Feature.java new file mode 100644 index 000000000..847c5cf5e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/Feature.java @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.util.ArrayList; + +/** + * + * Feature information + */ +public class Feature { + + private final String id; + private String version; + private String label; + private String image; + + private URLEntry description; + private URLEntry license; + private URLEntry copyright; + + private String installHandler; + private String installHandlerURL; + private String installHandlerLibrary; + + private URLEntry updateSite; + private ArrayList discoverySites; + + private ArrayList entries; + private String providerName; + private String os; + private String ws; + private String arch; + private String nl; + + private String location; + + public Feature(String id, String version) { + if (id == null) + throw new IllegalArgumentException(); + this.id = id; + this.version = version; + } + + public void addDiscoverySite(String label, String url) { + if (label == null && url == null) + return; + + if (this.discoverySites == null) + this.discoverySites = new ArrayList(); + + URLEntry entry = new URLEntry(url, label); + this.discoverySites.add(entry); + } + + public void addEntry(FeatureEntry plugin) { + if (entries == null) + entries = new ArrayList(); + entries.add(plugin); + } + + public String getArch() { + return arch; + } + + public String getCopyright() { + if (copyright != null) + return copyright.getAnnotation(); + return null; + } + + public String getCopyrightURL() { + if (copyright != null) + return copyright.getURL(); + return null; + } + + public String getDescription() { + if (description != null) + return description.getAnnotation(); + return null; + } + + public String getDescriptionURL() { + if (description != null) + return description.getURL(); + return null; + } + + public URLEntry[] getDiscoverySites() { + if (discoverySites == null) + return new URLEntry[0]; + return (URLEntry[]) discoverySites.toArray(new URLEntry[discoverySites.size()]); + } + + public FeatureEntry[] getEntries() { + if (entries == null) + return new FeatureEntry[0]; + return (FeatureEntry[]) entries.toArray(new FeatureEntry[entries.size()]); + } + + public String getId() { + return id; + } + + public String getImage() { + return image; + } + + public String getInstallHandler() { + return installHandler; + } + + public String getInstallHandlerLibrary() { + return installHandlerLibrary; + } + + public String getInstallHandlerURL() { + return installHandlerURL; + } + + public String getLabel() { + return label; + } + + public String getLicense() { + if (license != null) + return license.getAnnotation(); + return null; + } + + public String getLicenseURL() { + if (license != null) + return license.getURL(); + return null; + } + + public String getLocation() { + return this.location; + } + + public String getNL() { + return nl; + } + + public String getOS() { + return os; + } + + public String getProviderName() { + return providerName; + } + + public String getUpdateSiteLabel() { + if (updateSite != null) + return updateSite.getAnnotation(); + return null; + } + + public String getUpdateSiteURL() { + if (updateSite != null) + return updateSite.getURL(); + return null; + } + + public String getVersion() { + return version; + } + + public String getWS() { + return ws; + } + + public void setCopyright(String copyright) { + if (this.copyright == null) + this.copyright = new URLEntry(); + this.copyright.setAnnotation(copyright); + } + + public void setCopyrightURL(String copyrightURL) { + if (this.copyright == null) + this.copyright = new URLEntry(); + this.copyright.setURL(copyrightURL); + } + + public void setDescription(String description) { + if (this.description == null) + this.description = new URLEntry(); + this.description.setAnnotation(description); + } + + public void setDescriptionURL(String descriptionURL) { + if (this.description == null) + this.description = new URLEntry(); + this.description.setURL(descriptionURL); + } + + public void setEnvironment(String os, String ws, String arch, String nl) { + this.os = os; + this.ws = ws; + this.arch = arch; + this.nl = nl; + } + + public void setImage(String image) { + this.image = image; + } + + public void setInstallHandler(String installHandler) { + this.installHandler = installHandler; + } + + public void setInstallHandlerLibrary(String installHandlerLibrary) { + this.installHandlerLibrary = installHandlerLibrary; + } + + public void setInstallHandlerURL(String installHandlerURL) { + this.installHandlerURL = installHandlerURL; + } + + public void setLabel(String label) { + this.label = label; + } + + public void setLicense(String license) { + if (this.license == null) + this.license = new URLEntry(); + this.license.setAnnotation(license); + } + + public void setLicenseURL(String licenseURL) { + if (this.license == null) + this.license = new URLEntry(); + this.license.setURL(licenseURL); + } + + public void setLocation(String location) { + this.location = location; + } + + public void setProviderName(String value) { + providerName = value; + } + + public void setUpdateSiteLabel(String updateSiteLabel) { + if (this.updateSite == null) + this.updateSite = new URLEntry(); + this.updateSite.setAnnotation(updateSiteLabel); + } + + public void setUpdateSiteURL(String updateSiteURL) { + if (this.updateSite == null) + this.updateSite = new URLEntry(); + this.updateSite.setURL(updateSiteURL); + } + + public void setURL(String value) { + } + + public void setVersion(String version) { + this.version = version; + } + + /** + * For debugging purposes only. + */ + public String toString() { + return "Feature " + id + " version: " + version; //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/FeatureEntry.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/FeatureEntry.java new file mode 100644 index 000000000..ae974c445 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/FeatureEntry.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +/** + */ +public class FeatureEntry { + private final String id; + private final String version; + private String url; + private String os; + private String ws; + private String arch; + private String nl; + private String match; + private final boolean isPlugin; + private boolean isFragment = false; + private boolean isRequires = false; + private boolean unpack = true; + private boolean optional = false; + + /** + * Temporary field to add provisioning filters to features + */ + private String filter; + + public static FeatureEntry createRequires(String id, String version, String match, String filter, boolean isPlugin) { + FeatureEntry result = new FeatureEntry(id, version, isPlugin); + result.match = match; + result.isRequires = true; + // for requires we don't care what the form is so leave it as false (JAR'd) + result.unpack = false; + if (filter != null) + result.setFilter(filter); + return result; + } + + public FeatureEntry(String id, String version, boolean isPlugin) { + this.id = id; + this.version = version; + this.isPlugin = isPlugin; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final FeatureEntry other = (FeatureEntry) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (version == null) { + if (other.version != null) + return false; + } else if (!version.equals(other.version)) + return false; + return true; + } + + public String getArch() { + return arch; + } + + /** + * Temporary method to add provisioning filters to features + */ + public String getFilter() { + return filter; + } + + public String getId() { + return id; + } + + public String getMatch() { + return match; + } + + public String getNL() { + return nl; + } + + public String getOS() { + return os; + } + + public String getURL() { + return url; + } + + public String getVersion() { + return version; + } + + public String getWS() { + return ws; + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + public boolean isFragment() { + return isFragment; + } + + public boolean isOptional() { + return optional; + } + + public boolean isPlugin() { + return isPlugin; + } + + public boolean isRequires() { + return isRequires; + } + + public boolean isUnpack() { + return unpack; + } + + public void setEnvironment(String os, String ws, String arch, String nl) { + this.os = os; + this.ws = ws; + this.arch = arch; + this.nl = nl; + } + + /** + * Temporary method to add provisioning filters to features + */ + public void setFilter(String filter) { + this.filter = filter; + + } + + public void setFragment(boolean value) { + isFragment = value; + } + + public void setOptional(boolean value) { + optional = value; + } + + public void setUnpack(boolean value) { + unpack = value; + } + + public void setURL(String value) { + url = value; + } + + public String toString() { + StringBuffer result = new StringBuffer(); + + result.append(isPlugin ? "Plugin: " : "Feature: "); //$NON-NLS-1$ //$NON-NLS-2$ + result.append(id != null ? id.toString() : ""); //$NON-NLS-1$ + result.append(version != null ? " " + version.toString() : ""); //$NON-NLS-1$ //$NON-NLS-2$ + return result.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/FeatureParser.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/FeatureParser.java new file mode 100644 index 000000000..c69414071 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/FeatureParser.java @@ -0,0 +1,335 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.io.*; +import java.net.URL; +import java.util.Properties; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import javax.xml.parsers.*; +import org.eclipse.osgi.util.NLS; +import org.xml.sax.*; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Default feature parser. + * Parses the feature manifest file as defined by the platform. + * + * @since 3.0 + */ +public class FeatureParser extends DefaultHandler { + + private final static SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + private SAXParser parser; + private Feature result; + private URL url; + private StringBuffer characters = null; + + private Properties messages = null; + + public FeatureParser() { + this(true); + } + + protected FeatureParser(boolean createParser) { + super(); + if (!createParser) + return; + try { + parserFactory.setNamespaceAware(true); + this.parser = parserFactory.newSAXParser(); + } catch (ParserConfigurationException e) { + System.out.println(e); + } catch (SAXException e) { + System.out.println(e); + } + } + + public void characters(char[] ch, int start, int length) throws SAXException { + if (characters == null) + return; + characters.append(ch, start, length); + } + + protected Feature createFeature(String id, String version) { + return new Feature(id, version); + } + + public void endElement(String uri, String localName, String qName) throws SAXException { + if (characters == null) + return; + if ("description".equals(localName)) { //$NON-NLS-1$ + result.setDescription(localize(characters.toString().trim())); + } else if ("license".equals(localName)) { //$NON-NLS-1$ + result.setLicense(localize(characters.toString().trim())); + } else if ("copyright".equals(localName)) { //$NON-NLS-1$ + result.setCopyright(localize(characters.toString().trim())); + } + characters = null; + } + + public Feature getResult() { + return result; + } + + private Properties loadProperties(File directory) { + //skip directories that don't contain a feature.properties file + File file = new File(directory, "feature.properties"); //$NON-NLS-1$ + if (!file.exists()) + return null; + try { + InputStream input = new BufferedInputStream(new FileInputStream(file)); + try { + Properties result = new Properties(); + result.load(input); + return result; + } finally { + if (input != null) + input.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private Properties loadProperties(JarFile jar) { + JarEntry entry = jar.getJarEntry("feature.properties"); //$NON-NLS-1$ + if (entry == null) + return null; + try { + InputStream input = new BufferedInputStream(jar.getInputStream(entry)); + try { + Properties result = new Properties(); + result.load(input); + return result; + } finally { + if (input != null) + input.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private String localize(String value) { + if (messages == null || value == null) + return value; + if (!value.startsWith("%")) //$NON-NLS-1$ + return value; + return messages.getProperty(value.substring(1), value); + } + + /** + * Parses the specified location and constructs a feature. The given location + * should be either the location of the feature JAR or the directory containing + * the feature. + * + * @param location the location of the feature to parse. + */ + public Feature parse(File location) { + if (!location.exists()) + return null; + if (location.isDirectory()) { + //skip directories that don't contain a feature.xml file + File file = new File(location, "feature.xml"); //$NON-NLS-1$ + if (!file.exists()) + return null; + Properties properties = loadProperties(location); + try { + InputStream input = new BufferedInputStream(new FileInputStream(file)); + return parse(input, properties); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } else if (location.getName().endsWith(".jar")) { //$NON-NLS-1$ + try { + JarFile jar = new JarFile(location); + Properties properties = loadProperties(jar); + JarEntry entry = jar.getJarEntry("feature.xml"); //$NON-NLS-1$ + if (entry == null) + return null; + InputStream input = new BufferedInputStream(jar.getInputStream(entry)); + return parse(input, properties); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * Parse the given input stream and return a feature object + * or null. This method closes the input stream. + */ + public Feature parse(InputStream in, Properties messages) { + this.messages = messages; + result = null; + try { + parser.parse(new InputSource(in), this); + } catch (SAXException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + in.close(); + } catch (IOException e1) { + // Utils.log(e1.getLocalizedMessage()); + } + } + return result; + } + + private void processCopyright(Attributes attributes) { + result.setCopyrightURL(attributes.getValue("url")); //$NON-NLS-1$ + characters = new StringBuffer(); + } + + private void processDescription(Attributes attributes) { + result.setDescriptionURL(attributes.getValue("url")); //$NON-NLS-1$ + characters = new StringBuffer(); + } + + private void processDiscoverySite(Attributes attributes) { + result.addDiscoverySite(attributes.getValue("url"), attributes.getValue("label")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected void processFeature(Attributes attributes) { + String id = attributes.getValue("id"); //$NON-NLS-1$ + String ver = attributes.getValue("version"); //$NON-NLS-1$ + + if (id == null || id.trim().equals("") //$NON-NLS-1$ + || ver == null || ver.trim().equals("")) { //$NON-NLS-1$ + // System.out.println(NLS.bind(Messages.FeatureParser_IdOrVersionInvalid, (new String[] { id, ver}))); + } else { + result = createFeature(id, ver); + + String os = attributes.getValue("os"); //$NON-NLS-1$ + String ws = attributes.getValue("ws"); //$NON-NLS-1$ + String nl = attributes.getValue("nl"); //$NON-NLS-1$ + String arch = attributes.getValue("arch"); //$NON-NLS-1$ + result.setEnvironment(os, ws, arch, nl); + + //TODO rootURLs + if (url != null && "file".equals(url.getProtocol())) { //$NON-NLS-1$ + File f = new File(url.getFile().replace('/', File.separatorChar)); + result.setURL("features" + "/" + f.getParentFile().getName() + "/");// + f.getName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } else { + // externalized URLs might be in relative form, ensure they are absolute + // feature.setURL(Utils.makeAbsolute(Utils.getInstallURL(), url).toExternalForm()); + } + + result.setProviderName(localize(attributes.getValue("provider-name"))); //$NON-NLS-1$ + result.setLabel(localize(attributes.getValue("label"))); //$NON-NLS-1$ + result.setImage(attributes.getValue("image")); //$NON-NLS-1$ + + // Utils.debug("End process DefaultFeature tag: id:" +id + " ver:" +ver + " url:" + feature.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + private void processImport(Attributes attributes) { + String id = attributes.getValue("feature"); //$NON-NLS-1$ + FeatureEntry entry = null; + if (id != null) { + entry = FeatureEntry.createRequires(id, attributes.getValue("version"), attributes.getValue("match"), attributes.getValue("filter"), false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } else { + id = attributes.getValue("plugin"); //$NON-NLS-1$ + entry = FeatureEntry.createRequires(id, attributes.getValue("version"), attributes.getValue("match"), attributes.getValue("filter"), true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + result.addEntry(entry); + } + + private void processIncludes(Attributes attributes) { + FeatureEntry entry = new FeatureEntry(attributes.getValue("id"), attributes.getValue("version"), false); //$NON-NLS-1$ //$NON-NLS-2$ + String flag = attributes.getValue("optional"); //$NON-NLS-1$ + if (flag != null) + entry.setOptional(Boolean.valueOf(flag).booleanValue()); + setEnvironment(attributes, entry); + result.addEntry(entry); + } + + private void processInstallHandler(Attributes attributes) { + result.setInstallHandler(attributes.getValue("handler")); //$NON-NLS-1$ + result.setInstallHandlerLibrary(attributes.getValue("library")); //$NON-NLS-1$ + result.setInstallHandlerURL(attributes.getValue("url")); //$NON-NLS-1$ + } + + private void processLicense(Attributes attributes) { + result.setLicenseURL(attributes.getValue("url")); //$NON-NLS-1$ + characters = new StringBuffer(); + } + + private void processPlugin(Attributes attributes) { + String id = attributes.getValue("id"); //$NON-NLS-1$ + String version = attributes.getValue("version"); //$NON-NLS-1$ + + if (id == null || id.trim().equals("") || version == null || version.trim().equals("")) { //$NON-NLS-1$ //$NON-NLS-2$ + System.out.println(NLS.bind("FeatureParser#processPlugin, ID {0} or version {1} invalid", (new String[] {id, version}))); //$NON-NLS-1$ + } else { + FeatureEntry plugin = new FeatureEntry(id, version, true); + setEnvironment(attributes, plugin); + String unpack = attributes.getValue("unpack"); //$NON-NLS-1$ + if (unpack != null) + plugin.setUnpack(Boolean.valueOf(unpack).booleanValue()); + String fragment = attributes.getValue("fragment"); //$NON-NLS-1$ + if (fragment != null) + plugin.setFragment(Boolean.valueOf(fragment).booleanValue()); + String filter = attributes.getValue("filter"); //$NON-NLS-1$ + if (filter != null) + plugin.setFilter(filter); + result.addEntry(plugin); + + // Utils.debug("End process DefaultFeature tag: id:" + id + " ver:" + ver + " url:" + feature.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + private void processUpdateSite(Attributes attributes) { + result.setUpdateSiteLabel(attributes.getValue("label")); //$NON-NLS-1$ + result.setUpdateSiteURL(attributes.getValue("url")); //$NON-NLS-1$ + } + + private void setEnvironment(Attributes attributes, FeatureEntry entry) { + String os = attributes.getValue("os"); //$NON-NLS-1$ + String ws = attributes.getValue("ws"); //$NON-NLS-1$ + String nl = attributes.getValue("nl"); //$NON-NLS-1$ + String arch = attributes.getValue("arch"); //$NON-NLS-1$ + entry.setEnvironment(os, ws, arch, nl); + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + // Utils.debug("Start Element: uri:" + uri + " local Name:" + localName + " qName:" + qName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if ("plugin".equals(localName)) { //$NON-NLS-1$ + processPlugin(attributes); + } else if ("description".equals(localName)) { //$NON-NLS-1$ + processDescription(attributes); + } else if ("license".equals(localName)) { //$NON-NLS-1$ + processLicense(attributes); + } else if ("copyright".equals(localName)) { //$NON-NLS-1$ + processCopyright(attributes); + } else if ("feature".equals(localName)) { //$NON-NLS-1$ + processFeature(attributes); + } else if ("import".equals(localName)) { //$NON-NLS-1$ + processImport(attributes); + } else if ("includes".equals(localName)) { //$NON-NLS-1$ + processIncludes(attributes); + } else if ("install-handler".equals(localName)) { //$NON-NLS-1$ + processInstallHandler(attributes); + } else if ("update".equals(localName)) { //$NON-NLS-1$ + processUpdateSite(attributes); + } else if ("discovery".equals(localName)) { //$NON-NLS-1$ + processDiscoverySite(attributes); + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/Messages.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/Messages.java new file mode 100644 index 000000000..7afe31e63 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/Messages.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import org.eclipse.osgi.util.NLS; + +public final class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.update.internal.core.messages";//$NON-NLS-1$ + + public static String DefaultFeatureParser_IdOrVersionInvalid; + public static String DefaultSiteParser_NoSiteTag; + public static String DefaultSiteParser_WrongParsingStack; + public static String DefaultSiteParser_UnknownElement; + public static String DefaultSiteParser_UnknownStartState; + public static String DefaultSiteParser_Missing; + public static String DefaultSiteParser_ParsingStackBackToInitialState; + public static String DefaultSiteParser_ElementAlreadySet; + public static String DefaultSiteParser_CategoryAlreadySet; + public static String DefaultSiteParser_UnknownEndState; + public static String DefaultSiteParser_ErrorParsing; + public static String DefaultSiteParser_ErrorlineColumnMessage; + public static String DefaultSiteParser_ErrorParsingSite; + public static String DefaultSiteParser_UnknownState; + public static String DefaultSiteParser_InvalidXMLStream; + public static String DefaultSiteParser_mirrors; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + // Do not instantiate + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/ProductFile.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/ProductFile.java new file mode 100644 index 000000000..553c488ce --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/ProductFile.java @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright (c) 2005, 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 + *******************************************************************************/ + +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.io.*; +import java.util.*; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.eclipse.equinox.internal.p2.publisher.IProductDescriptor; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * + * @since 3.1 + */ +public class ProductFile extends DefaultHandler implements IProductDescriptor { + private final static SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + + private static final String PROGRAM_ARGS = "programArgs"; //$NON-NLS-1$ + private static final String PROGRAM_ARGS_LINUX = "programArgsLin"; //$NON-NLS-1$ + private static final String PROGRAM_ARGS_MAC = "programArgsMac"; //$NON-NLS-1$ + private static final String PROGRAM_ARGS_SOLARIS = "programArgsSol"; //$NON-NLS-1$ + private static final String PROGRAM_ARGS_WIN = "programArgsWin"; //$NON-NLS-1$ + private static final String VM_ARGS = "vmArgs"; //$NON-NLS-1$ + private static final String VM_ARGS_LINUX = "vmArgsLin"; //$NON-NLS-1$ + private static final String VM_ARGS_MAC = "vmArgsMac"; //$NON-NLS-1$ + private static final String VM_ARGS_SOLARIS = "vmArgsSol"; //$NON-NLS-1$ + private static final String VM_ARGS_WIN = "vmArgsWin"; //$NON-NLS-1$ + + private static final String SOLARIS_LARGE = "solarisLarge"; //$NON-NLS-1$ + private static final String SOLARIS_MEDIUM = "solarisMedium"; //$NON-NLS-1$ + private static final String SOLARIS_SMALL = "solarisSmall"; //$NON-NLS-1$ + private static final String SOLARIS_TINY = "solarisTiny"; //$NON-NLS-1$ + private static final String WIN32_16_LOW = "winSmallLow"; //$NON-NLS-1$ + private static final String WIN32_16_HIGH = "winSmallHigh"; //$NON-NLS-1$ + private static final String WIN32_24_LOW = "win24Low"; //$NON-NLS-1$ + private static final String WIN32_32_LOW = "winMediumLow"; //$NON-NLS-1$ + private static final String WIN32_32_HIGH = "winMediumHigh"; //$NON-NLS-1$ + private static final String WIN32_48_LOW = "winLargeLow"; //$NON-NLS-1$ + private static final String WIN32_48_HIGH = "winLargeHigh"; //$NON-NLS-1$ + + private static final String OS_WIN32 = "win32";//$NON-NLS-1$ + private static final String OS_LINUX = "linux";//$NON-NLS-1$ + private static final String OS_SOLARIS = "solaris";//$NON-NLS-1$ + private static final String OS_MACOSX = "macosx";//$NON-NLS-1$ + + private static final String PRODUCT = "product"; //$NON-NLS-1$ + private static final String CONFIG_INI = "configIni"; //$NON-NLS-1$ + private static final String LAUNCHER = "launcher"; //$NON-NLS-1$ + private static final String LAUNCHER_ARGS = "launcherArgs"; //$NON-NLS-1$ + private static final String PLUGINS = "plugins"; //$NON-NLS-1$ + private static final String FEATURES = "features"; //$NON-NLS-1$ + private static final String SPLASH = "splash"; //$NON-NLS-1$ + private static final String P_USE_ICO = "useIco"; //$NON-NLS-1$ + + //These constants form a small state machine to parse the .product file + private static final int STATE_START = 0; + private static final int STATE_PRODUCT = 1; + private static final int STATE_LAUNCHER = 2; + private static final int STATE_LAUNCHER_ARGS = 3; + private static final int STATE_PLUGINS = 4; + private static final int STATE_FEATURES = 5; + private static final int STATE_PROGRAM_ARGS = 6; + private static final int STATE_PROGRAM_ARGS_LINUX = 7; + private static final int STATE_PROGRAM_ARGS_MAC = 8; + private static final int STATE_PROGRAM_ARGS_SOLARIS = 9; + private static final int STATE_PROGRAM_ARGS_WIN = 10; + private static final int STATE_VM_ARGS = 11; + private static final int STATE_VM_ARGS_LINUX = 12; + private static final int STATE_VM_ARGS_MAC = 13; + private static final int STATE_VM_ARGS_SOLARIS = 14; + private static final int STATE_VM_ARGS_WIN = 15; + + private int state = STATE_START; + + private final SAXParser parser; + private String currentOS = null; + private boolean useIco = false; + private final ArrayList result = new ArrayList(6); + private String launcherName = null; + private String icons[] = null; + private String configPath = null; + private String id = null; + private boolean useFeatures = false; + private List plugins = null; + private List fragments = null; + private List features = null; + private String splashLocation = null; + private String productName = null; + private String application = null; + private String version = null; + + private Properties launcherArgs = new Properties(); + + private static String normalize(String text) { + if (text == null || text.trim().length() == 0) + return ""; //$NON-NLS-1$ + + text = text.replaceAll("\\r|\\n|\\f|\\t", " "); //$NON-NLS-1$ //$NON-NLS-2$ + return text.replaceAll("\\s+", " "); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Constructs a feature parser. + */ + public ProductFile(String location, String os) throws Exception { + super(); + this.currentOS = os; + // try { + parserFactory.setNamespaceAware(true); + parser = parserFactory.newSAXParser(); + InputStream in = new BufferedInputStream(new FileInputStream(location)); + parser.parse(new InputSource(in), this); + // } catch (ParserConfigurationException e) { + // throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FORMAT, NLS.bind(Messages.exception_productParse, location), e)); + // } catch (SAXException e) { + // throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FORMAT, NLS.bind(Messages.exception_productParse, location), e)); + // } catch (FileNotFoundException e) { + // throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FILE, NLS.bind(Messages.exception_missingElement, location), null)); + // } catch (IOException e) { + // throw new CoreException(new Status(IStatus.ERROR, PI_PDEBUILD, EXCEPTION_PRODUCT_FORMAT, NLS.bind(Messages.exception_productParse, location), e)); + // } + } + + public String getLauncherName() { + return launcherName; + } + + public List getPlugins() { + return getPlugins(true); + } + + public List getPlugins(boolean includeFragments) { + List p = plugins != null ? plugins : Collections.EMPTY_LIST; + if (!includeFragments) + return p; + + List f = fragments != null ? fragments : Collections.EMPTY_LIST; + int size = p.size() + f.size(); + if (size == 0) + return Collections.EMPTY_LIST; + + List both = new ArrayList(size); + both.addAll(p); + both.addAll(f); + return both; + } + + public List getFragments() { + if (fragments == null) + return Collections.EMPTY_LIST; + return fragments; + } + + public List getFeatures() { + if (features == null) + return Collections.EMPTY_LIST; + return features; + } + + public boolean containsPlugin(String plugin) { + return (plugins != null && plugins.contains(plugin)) || (fragments != null && fragments.contains(plugin)); + } + + /** + * Parses the specified url and constructs a feature + */ + public String[] getIcons() { + if (icons != null) + return icons; + String[] temp = new String[result.size()]; + int i = 0; + for (Iterator iter = result.iterator(); iter.hasNext();) { + String element = (String) iter.next(); + if (element != null) + temp[i++] = element; + } + icons = new String[i]; + System.arraycopy(temp, 0, icons, 0, i); + return icons; + } + + public String getConfigIniPath() { + return configPath; + } + + public String getId() { + return id; + } + + public String getSplashLocation() { + return splashLocation; + } + + public String getProductName() { + return productName; + } + + public String getApplication() { + return application; + } + + public boolean useFeatures() { + return useFeatures; + } + + public String getVersion() { + return (version == null) ? "0.0.0" : version; //$NON-NLS-1$ + } + + public String getVMArguments(String os) { + String key = null; + if (os.equals(OS_WIN32)) { + key = VM_ARGS_WIN; + } else if (os.equals(OS_LINUX)) { + key = VM_ARGS_LINUX; + } else if (os.equals(OS_MACOSX)) { + key = VM_ARGS_MAC; + } else if (os.equals(OS_SOLARIS)) { + key = VM_ARGS_SOLARIS; + } + + String prefix = launcherArgs.getProperty(VM_ARGS); + String platform = null, args = null; + if (key != null) + platform = launcherArgs.getProperty(key); + if (prefix != null) + args = platform != null ? prefix + " " + platform : prefix; //$NON-NLS-1$ + else + args = platform != null ? platform : ""; //$NON-NLS-1$ + return normalize(args); + } + + public String getProgramArguments(String os) { + String key = null; + if (os.equals(OS_WIN32)) { + key = PROGRAM_ARGS_WIN; + } else if (os.equals(OS_LINUX)) { + key = PROGRAM_ARGS_LINUX; + } else if (os.equals(OS_MACOSX)) { + key = PROGRAM_ARGS_MAC; + } else if (os.equals(OS_SOLARIS)) { + key = PROGRAM_ARGS_SOLARIS; + } + + String prefix = launcherArgs.getProperty(PROGRAM_ARGS); + String platform = null, args = null; + if (key != null) + platform = launcherArgs.getProperty(key); + if (prefix != null) + args = platform != null ? prefix + " " + platform : prefix; //$NON-NLS-1$ + else + args = platform != null ? platform : ""; //$NON-NLS-1$ + return normalize(args); + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) { + switch (state) { + case STATE_START : + if (PRODUCT.equals(localName)) { + processProduct(attributes); + state = STATE_PRODUCT; + } + break; + + case STATE_PRODUCT : + if (CONFIG_INI.equals(localName)) { + processConfigIni(attributes); + } else if (LAUNCHER.equals(localName)) { + processLauncher(attributes); + state = STATE_LAUNCHER; + } else if (PLUGINS.equals(localName)) { + state = STATE_PLUGINS; + } else if (FEATURES.equals(localName)) { + state = STATE_FEATURES; + } else if (LAUNCHER_ARGS.equals(localName)) { + state = STATE_LAUNCHER_ARGS; + } else if (SPLASH.equals(localName)) { + splashLocation = attributes.getValue("location"); //$NON-NLS-1$ + } + break; + + case STATE_LAUNCHER : + if (OS_SOLARIS.equals(localName)) { + processSolaris(attributes); + } else if ("win".equals(localName)) { //$NON-NLS-1$ + processWin(attributes); + } else if (OS_LINUX.equals(localName)) { + processLinux(attributes); + } else if (OS_MACOSX.equals(localName)) { + processMac(attributes); + } + if ("ico".equals(localName)) { //$NON-NLS-1$ + processIco(attributes); + } else if ("bmp".equals(localName)) { //$NON-NLS-1$ + processBmp(attributes); + } + break; + + case STATE_LAUNCHER_ARGS : + if (PROGRAM_ARGS.equals(localName)) { + state = STATE_PROGRAM_ARGS; + } else if (PROGRAM_ARGS_LINUX.equals(localName)) { + state = STATE_PROGRAM_ARGS_LINUX; + } else if (PROGRAM_ARGS_MAC.equals(localName)) { + state = STATE_PROGRAM_ARGS_MAC; + } else if (PROGRAM_ARGS_SOLARIS.equals(localName)) { + state = STATE_PROGRAM_ARGS_SOLARIS; + } else if (PROGRAM_ARGS_WIN.equals(localName)) { + state = STATE_PROGRAM_ARGS_WIN; + } else if (VM_ARGS.equals(localName)) { + state = STATE_VM_ARGS; + } else if (VM_ARGS_LINUX.equals(localName)) { + state = STATE_VM_ARGS_LINUX; + } else if (VM_ARGS_MAC.equals(localName)) { + state = STATE_VM_ARGS_MAC; + } else if (VM_ARGS_SOLARIS.equals(localName)) { + state = STATE_VM_ARGS_SOLARIS; + } else if (VM_ARGS_WIN.equals(localName)) { + state = STATE_VM_ARGS_WIN; + } + break; + + case STATE_PLUGINS : + if ("plugin".equals(localName)) { //$NON-NLS-1$ + processPlugin(attributes); + } + break; + + case STATE_FEATURES : + if ("feature".equals(localName)) { //$NON-NLS-1$ + processFeature(attributes); + } + break; + } + } + + public void endElement(String uri, String localName, String qName) { + switch (state) { + case STATE_PLUGINS : + if (PLUGINS.equals(localName)) + state = STATE_PRODUCT; + break; + case STATE_FEATURES : + if (FEATURES.equals(localName)) + state = STATE_PRODUCT; + break; + case STATE_LAUNCHER_ARGS : + if (LAUNCHER_ARGS.equals(localName)) + state = STATE_PRODUCT; + break; + case STATE_LAUNCHER : + if (LAUNCHER.equals(localName)) + state = STATE_PRODUCT; + break; + + case STATE_PROGRAM_ARGS : + case STATE_PROGRAM_ARGS_LINUX : + case STATE_PROGRAM_ARGS_MAC : + case STATE_PROGRAM_ARGS_SOLARIS : + case STATE_PROGRAM_ARGS_WIN : + case STATE_VM_ARGS : + case STATE_VM_ARGS_LINUX : + case STATE_VM_ARGS_MAC : + case STATE_VM_ARGS_SOLARIS : + case STATE_VM_ARGS_WIN : + state = STATE_LAUNCHER_ARGS; + break; + } + } + + public void characters(char[] ch, int start, int length) { + switch (state) { + case STATE_PROGRAM_ARGS : + addLaunchArgumentToMap(PROGRAM_ARGS, String.valueOf(ch, start, length)); + break; + case STATE_PROGRAM_ARGS_LINUX : + addLaunchArgumentToMap(PROGRAM_ARGS_LINUX, String.valueOf(ch, start, length)); + break; + case STATE_PROGRAM_ARGS_MAC : + addLaunchArgumentToMap(PROGRAM_ARGS_MAC, String.valueOf(ch, start, length)); + break; + case STATE_PROGRAM_ARGS_SOLARIS : + addLaunchArgumentToMap(PROGRAM_ARGS_SOLARIS, String.valueOf(ch, start, length)); + break; + case STATE_PROGRAM_ARGS_WIN : + addLaunchArgumentToMap(PROGRAM_ARGS_WIN, String.valueOf(ch, start, length)); + break; + case STATE_VM_ARGS : + addLaunchArgumentToMap(VM_ARGS, String.valueOf(ch, start, length)); + break; + case STATE_VM_ARGS_LINUX : + addLaunchArgumentToMap(VM_ARGS_LINUX, String.valueOf(ch, start, length)); + break; + case STATE_VM_ARGS_MAC : + addLaunchArgumentToMap(VM_ARGS_MAC, String.valueOf(ch, start, length)); + break; + case STATE_VM_ARGS_SOLARIS : + addLaunchArgumentToMap(VM_ARGS_SOLARIS, String.valueOf(ch, start, length)); + break; + case STATE_VM_ARGS_WIN : + addLaunchArgumentToMap(VM_ARGS_WIN, String.valueOf(ch, start, length)); + break; + } + } + + private void addLaunchArgumentToMap(String key, String value) { + if (launcherArgs == null) + launcherArgs = new Properties(); + + String oldValue = launcherArgs.getProperty(key); + if (oldValue != null) + launcherArgs.setProperty(key, oldValue + value); + else + launcherArgs.setProperty(key, value); + } + + private void processPlugin(Attributes attributes) { + String fragment = attributes.getValue("fragment"); //$NON-NLS-1$ + if (fragment != null && new Boolean(fragment).booleanValue()) { + if (fragments == null) + fragments = new ArrayList(); + fragments.add(attributes.getValue("id")); //$NON-NLS-1$ + } else { + if (plugins == null) + plugins = new ArrayList(); + plugins.add(attributes.getValue("id")); //$NON-NLS-1$ + } + } + + private void processFeature(Attributes attributes) { + if (features == null) + features = new ArrayList(); + features.add(attributes.getValue("id")); //$NON-NLS-1$ + } + + private void processProduct(Attributes attributes) { + id = attributes.getValue("id"); //$NON-NLS-1$ + productName = attributes.getValue("name"); //$NON-NLS-1$ + application = attributes.getValue("application"); //$NON-NLS-1$ + String use = attributes.getValue("useFeatures"); //$NON-NLS-1$ + if (use != null) + useFeatures = Boolean.valueOf(use).booleanValue(); + version = attributes.getValue("version"); //$NON-NLS-1$ + } + + private void processConfigIni(Attributes attributes) { + if (attributes.getValue("use").equals("custom")) { //$NON-NLS-1$//$NON-NLS-2$ + configPath = attributes.getValue("path"); //$NON-NLS-1$ + } + } + + private void processLauncher(Attributes attributes) { + launcherName = attributes.getValue("name"); //$NON-NLS-1$ + } + + private boolean osMatch(String os) { + if (os == currentOS) + return true; + if (os == null) + return false; + return os.equals(currentOS); + } + + private void processSolaris(Attributes attributes) { + if (!osMatch(OS_SOLARIS)) + return; + result.add(attributes.getValue(SOLARIS_LARGE)); + result.add(attributes.getValue(SOLARIS_MEDIUM)); + result.add(attributes.getValue(SOLARIS_SMALL)); + result.add(attributes.getValue(SOLARIS_TINY)); + } + + private void processWin(Attributes attributes) { + if (!osMatch(OS_WIN32)) + return; + useIco = Boolean.valueOf(attributes.getValue(P_USE_ICO)).booleanValue(); + } + + private void processIco(Attributes attributes) { + if (!osMatch(OS_WIN32) || !useIco) + return; + result.add(attributes.getValue("path")); //$NON-NLS-1$ + } + + private void processBmp(Attributes attributes) { + if (!osMatch(OS_WIN32) || useIco) + return; + result.add(attributes.getValue(WIN32_16_HIGH)); + result.add(attributes.getValue(WIN32_16_LOW)); + result.add(attributes.getValue(WIN32_24_LOW)); + result.add(attributes.getValue(WIN32_32_HIGH)); + result.add(attributes.getValue(WIN32_32_LOW)); + result.add(attributes.getValue(WIN32_48_HIGH)); + result.add(attributes.getValue(WIN32_48_LOW)); + } + + private void processLinux(Attributes attributes) { + if (!osMatch(OS_LINUX)) + return; + result.add(attributes.getValue("icon")); //$NON-NLS-1$ + } + + private void processMac(Attributes attributes) { + if (!osMatch(OS_MACOSX)) + return; + result.add(attributes.getValue("icon")); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteCategory.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteCategory.java new file mode 100644 index 000000000..18e75f4f7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteCategory.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Comparator; + +/** + * A category in an update site. + * + * Based on org.eclipse.update.core.model.CategoryModel. + */ +public class SiteCategory { + + private static Comparator comp; + private String description; + private String label; + private String name; + + /** + * Returns a comparator for category models. + * + * @return comparator + * @since 2.0 + */ + public static Comparator getComparator() { + if (comp == null) { + comp = new Comparator() { + /* + * @see Comparator#compare(Object,Object) + * Returns 0 if versions are equal. + * Returns -1 if object1 is after than object2. + * Returns +1 if object1 is before than object2. + */ + public int compare(Object o1, Object o2) { + + SiteCategory cat1 = (SiteCategory) o1; + SiteCategory cat2 = (SiteCategory) o2; + + if (cat1.equals(cat2)) + return 0; + return cat1.getName().compareTo(cat2.getName()); + } + }; + } + return comp; + } + + /** + * Creates an uninitialized model object. + * + * @since 2.0 + */ + public SiteCategory() { + super(); + } + + /** + * Compare two category models for equality. + * + * @see Object#equals(Object) + * @since 2.0 + */ + public boolean equals(Object obj) { + boolean result = false; + if (obj instanceof SiteCategory) { + SiteCategory otherCategory = (SiteCategory) obj; + result = getName().equalsIgnoreCase(otherCategory.getName()); + } + return result; + } + + /** + * Retrieve the detailed category description + * + * @return category description, or <code>null</code>. + * @since 2.0 + */ + public String getDescription() { + return description; + } + + /** + * Retrieve the non-localized displayable label for the category. + * + * @return non-localized displayable label, or <code>null</code>. + * @since 2.0 + */ + public String getLabel() { + return label; + } + + /** + * Retrieve the name of the category. + * + * @return category name, or <code>null</code>. + * @since 2.0 + */ + public String getName() { + return name; + } + + /** + * Compute hash code for category model. + * + * @see Object#hashCode() + * @since 2.0 + */ + public int hashCode() { + return getName().hashCode(); + } + + /** + * Resolve the model object. + * Any URL strings in the model are resolved relative to the + * base URL argument. Any translatable strings in the model that are + * specified as translation keys are localized using the supplied + * resource bundle. + * + * @param base URL + * @param bundleURL resource bundle URL + * @exception MalformedURLException + * @since 2.0 + */ + public void resolve(URL base, URL bundleURL) throws MalformedURLException { + // resolve local elements + // localizedLabel = resolveNLString(bundleURL, label); + + // delegate to references + // resolveReference(getDescriptionModel(), base, bundleURL); + } + + /** + * Sets the category description. + * Throws a runtime exception if this object is marked read-only. + * + * @param description category description + * @since 2.0 + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Sets the category displayable label. + * Throws a runtime exception if this object is marked read-only. + * + * @param label displayable label, or resource key + * @since 2.0 + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * Sets the category name. + * Throws a runtime exception if this object is marked read-only. + * + * @param name category name + * @since 2.0 + */ + public void setName(String name) { + this.name = name; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteFeature.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteFeature.java new file mode 100644 index 000000000..a9f43a016 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteFeature.java @@ -0,0 +1,408 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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 + * James D Miles (IBM Corp.) - bug 191783, NullPointerException in FeatureDownloader + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; + +/** + * A reference to a feature in an update site.xml file. + * + * Based on org.eclipse.update.core.model.FeatureReferenceModel. + */ +public class SiteFeature { + + private String arch; + // performance + private URL base; + private List /* of String*/categoryNames; + private String featureId; + private String featureVersion; + private String label; + private String nl; + + private String os; + private String patch; + private final boolean resolved = false; + private SiteModel site; + private String type; + private URL url; + private String urlString; + private String ws; + + /* + * Compares two URL for equality + * Return false if one of them is null + */ + public static boolean sameURL(URL url1, URL url2) { + + if (url1 == null || url2 == null) + return false; + if (url1 == url2) + return true; + if (url1.equals(url2)) + return true; + + // check if URL are file: URL as we may + // have 2 URL pointing to the same featureReference + // but with different representation + // (i.e. file:/C;/ and file:C:/) + if (!"file".equalsIgnoreCase(url1.getProtocol())) //$NON-NLS-1$ + return false; + if (!"file".equalsIgnoreCase(url2.getProtocol())) //$NON-NLS-1$ + return false; + + File file1 = new File(url1.getFile()); + File file2 = new File(url2.getFile()); + + if (file1 == null) + return false; + + return (file1.equals(file2)); + } + + /** + * Creates an uninitialized feature reference model object. + */ + public SiteFeature() { + super(); + } + + /** + * Adds the name of a category this feature belongs to. + * Throws a runtime exception if this object is marked read-only. + * + * @param categoryName category name + */ + public void addCategoryName(String categoryName) { + if (this.categoryNames == null) + this.categoryNames = new ArrayList(); + if (!this.categoryNames.contains(categoryName)) + this.categoryNames.add(categoryName); + } + + private void delayedResolve() { + + // PERF: delay resolution + if (resolved) + return; + + // resolve local elements + try { + url = new URL(base, urlString); + } catch (MalformedURLException e) { + // UpdateCore.warn("", e); //$NON-NLS-1$ + } + } + + /** + * Compares 2 feature reference models for equality + * + * @param object feature reference model to compare with + * @return <code>true</code> if the two models are equal, + * <code>false</code> otherwise + */ + public boolean equals(Object object) { + + if (object == null) + return false; + if (getURL() == null) + return false; + + if (!(object instanceof SiteFeature)) + return false; + + SiteFeature f = (SiteFeature) object; + + return sameURL(getURL(), f.getURL()); + } + + /** + * Returns the names of categories the referenced feature belongs to. + * + * @return an array of names, or an empty array. + */ + public String[] getCategoryNames() { + if (categoryNames == null) + return new String[0]; + + return (String[]) categoryNames.toArray(new String[0]); + } + + /** + * Returns the feature identifier as a string + * + * @return feature identifier + */ + public String getFeatureIdentifier() { + return featureId; + } + + /** + * Returns the feature version as a string + * + * @return feature version + */ + public String getFeatureVersion() { + return featureVersion; + } + + /** + * Retrieve the displayable label for the feature reference. If the model + * object has been resolved, the label is localized. + * + * @return displayable label, or <code>null</code>. + */ + public String getLabel() { + return label; + } + + /** + * Retrieve the non-localized displayable label for the feature reference. + * + * @return non-localized displayable label, or <code>null</code>. + */ + public String getLabelNonLocalized() { + return label; + } + + /** + * Get optional locale specification as a comma-separated string. + * + * @return the locale specification string, or <code>null</code>. + */ + public String getNL() { + return nl; + } + + /** + * Get optional operating system specification as a comma-separated string. + * + * @return the operating system specification string, or <code>null</code>. + */ + public String getOS() { + return os; + } + + /** + * Get optional system architecture specification as a comma-separated string. + * + * @return the system architecture specification string, or <code>null</code>. + */ + public String getOSArch() { + return arch; + } + + /** + * Returns the patch mode. + */ + public String getPatch() { + return patch; + } + + /** + * Returns the site model for the reference. + * + * @return site model + * @since 2.0 + */ + public SiteModel getSiteModel() { + return site; + } + + /** + * Returns the referenced feature type. + * + * @return feature type, or <code>null</code> representing the default + * feature type for the site + */ + public String getType() { + return type; + } + + /** + * Returns the resolved URL for the feature reference. + * + * @return url string + */ + public URL getURL() { + delayedResolve(); + return url; + } + + /** + * Returns the unresolved URL string for the reference. + * + * @return url string + */ + public String getURLString() { + return urlString; + } + + /** + * Get optional windowing system specification as a comma-separated string. + * + * @return the windowing system specification string, or <code>null</code>. + */ + public String getWS() { + return ws; + } + + /** + * Resolve the model object. + * Any URL strings in the model are resolved relative to the + * base URL argument. Any translatable strings in the model that are + * specified as translation keys are localized using the supplied + * resource bundle. + * + * @param resolveBase URL + * @param bundleURL resource bundle URL + * @exception MalformedURLException + */ + public void resolve(URL resolveBase, URL bundleURL) throws MalformedURLException { + this.base = resolveBase; + } + + /** + * Sets the system architecture specification. + * Throws a runtime exception if this object is marked read-only. + * + * @param arch system architecture specification as a comma-separated list + */ + public void setArch(String arch) { + this.arch = arch; + } + + /** + * Sets the names of categories this feature belongs to. + * Throws a runtime exception if this object is marked read-only. + * + * @param categoryNames an array of category names + */ + public void setCategoryNames(String[] categoryNames) { + if (categoryNames == null) + this.categoryNames = null; + else + this.categoryNames = new ArrayList(Arrays.asList(categoryNames)); + } + + /** + * Sets the feature identifier. + * Throws a runtime exception if this object is marked read-only. + * + * @param featureId feature identifier + */ + public void setFeatureIdentifier(String featureId) { + this.featureId = featureId; + } + + /** + * Sets the feature version. + * Throws a runtime exception if this object is marked read-only. + * + * @param featureVersion feature version + */ + public void setFeatureVersion(String featureVersion) { + this.featureVersion = featureVersion; + } + + /** + * Sets the label. + * @param label The label to set + */ + public void setLabel(String label) { + this.label = label; + } + + /** + * Sets the locale specification. + * Throws a runtime exception if this object is marked read-only. + * + * @param nl locale specification as a comma-separated list + */ + public void setNL(String nl) { + this.nl = nl; + } + + /** + * Sets the operating system specification. + * Throws a runtime exception if this object is marked read-only. + * + * @param os operating system specification as a comma-separated list + */ + public void setOS(String os) { + this.os = os; + } + + /** + * Sets the patch mode. + */ + public void setPatch(String patch) { + this.patch = patch; + } + + /** + * Sets the site for the referenced. + * Throws a runtime exception if this object is marked read-only. + * + * @param site site for the reference + */ + public void setSiteModel(SiteModel site) { + this.site = site; + } + + /** + * Sets the referenced feature type. + * Throws a runtime exception if this object is marked read-only. + * + * @param type referenced feature type + */ + public void setType(String type) { + this.type = type; + } + + /** + * Sets the unresolved URL for the feature reference. + * Throws a runtime exception if this object is marked read-only. + * + * @param urlString unresolved URL string + */ + public void setURLString(String urlString) { + this.urlString = urlString; + this.url = null; + } + + /** + * Sets the windowing system specification. + * Throws a runtime exception if this object is marked read-only. + * + * @param ws windowing system specification as a comma-separated list + */ + public void setWS(String ws) { + this.ws = ws; + } + + /** + * @see Object#toString() + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(getClass().toString() + " :"); //$NON-NLS-1$ + buffer.append(" at "); //$NON-NLS-1$ + if (url != null) + buffer.append(url.toExternalForm()); + return buffer.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteModel.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteModel.java new file mode 100644 index 000000000..8d5da13da --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/SiteModel.java @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright (c) 2000, 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 + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.publisher.features; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; + +/** + * A model of an update site. + * + * Copied from org.eclipse.update.core.model.SiteModel. + */ +public class SiteModel { + + private List /*of ArchiveReferenceModel*/archiveReferences; + /** + * Map of String (category id) -> SiteCategory + */ + private Map categories; + private URLEntry description; + /** + * Map of String (feature id) -> SiteFeature + */ + private List features; + private URL locationURL; + private String locationURLString; + private List /* of URLEntry */mirrors; + private String mirrorsURLString; + private boolean supportsPack200; + private String type; + + /** + * Creates an uninitialized site model object. + * + * @since 2.0 + */ + public SiteModel() { + super(); + } + + /** + * Adds an archive reference model to site. + * Throws a runtime exception if this object is marked read-only. + * + * @param archiveReference archive reference model + * @since 2.0 + */ + public void addArchive(URLEntry archiveReference) { + if (this.archiveReferences == null) + this.archiveReferences = new ArrayList(); + if (!this.archiveReferences.contains(archiveReference)) + this.archiveReferences.add(archiveReference); + } + + /** + * Adds a category to the site. + * + * @param category category model + */ + public void addCategory(SiteCategory category) { + if (categories == null) + categories = new HashMap(); + if (!categories.containsKey(category.getName())) + categories.put(category.getName(), category); + } + + /** + * Adds a feature reference model to site. + * + * @param featureReference feature reference model + */ + public void addFeature(SiteFeature featureReference) { + if (this.features == null) + this.features = new ArrayList(); + this.features.add(featureReference); + } + + /** + * Adds a mirror site. + * + * @param mirror mirror model + * @since 3.1 + */ + public void addMirror(URLEntry mirror) { + if (this.mirrors == null) + this.mirrors = new ArrayList(); + if (!this.mirrors.contains(mirror)) + this.mirrors.add(mirror); + } + + private void doSetMirrorSiteEntryModels(URLEntry[] newMirrors) { + if (newMirrors == null || newMirrors.length == 0) + this.mirrors = null; + else + this.mirrors = new ArrayList(Arrays.asList(newMirrors)); + } + + /** + * Returns an array of plug-in and non-plug-in archive reference models + * on this site + * + * @return an array of archive reference models, or an empty array if there are + * no archives known to this site. + * @since 2.0 + */ + public URLEntry[] getArchives() { + if (archiveReferences == null || archiveReferences.size() == 0) + return new URLEntry[0]; + + return (URLEntry[]) archiveReferences.toArray(new URLEntry[0]); + } + + /** + * Returns an array of category models for this site. + * + * @return array of site category models, or an empty array. + * @since 2.0 + */ + public SiteCategory[] getCategories() { + if (categories == null || categories.size() == 0) + return new SiteCategory[0]; + return (SiteCategory[]) categories.values().toArray(new SiteCategory[0]); + } + + /** + * Returns the category with the given name. + * @return the category with the given name, or <code>null</code> + */ + public SiteCategory getCategory(String name) { + return (SiteCategory) (categories == null ? null : categories.get(name)); + } + + /** + * Returns the site description. + * + * @return site description, or <code>null</code>. + */ + public URLEntry getDescription() { + return description; + } + + /** + * Returns an array of feature reference models on this site. + * + * @return an array of feature reference models, or an empty array. + */ + public SiteFeature[] getFeatures() { + if (features == null || features.size() == 0) + return new SiteFeature[0]; + return (SiteFeature[]) features.toArray(new SiteFeature[0]); + } + + /** + * Returns the resolved URL for the site. + * + * @return url, or <code>null</code> + */ + public URL getLocationURL() { + return locationURL; + } + + /** + * Returns the unresolved URL string for the site. + * + * @return url string, or <code>null</code> + */ + public String getLocationURLString() { + return locationURLString; + } + + /** + * Return an array of update site mirrors + * + * @return an array of mirror entries, or an empty array. + * @since 3.1 + */ + public URLEntry[] getMirrors() { + //delayedResolve(); no delay; + if (mirrors == null || mirrors.size() == 0) + // see if we can get mirrors from the provided url + if (mirrorsURLString != null) + doSetMirrorSiteEntryModels(DefaultSiteParser.getMirrors(mirrorsURLString)); + + if (mirrors == null || mirrors.size() == 0) + return new URLEntry[0]; + return (URLEntry[]) mirrors.toArray(new URLEntry[0]); + } + + /** + * Returns the URL from which the list of mirrors of this site can be retrieved. + * + * @since org.eclipse.equinox.p2.metadata.generator 1.0 + */ + public String getMirrorsURL() { + return mirrorsURLString; + } + + /** + * Returns the site type. + * + * @return site type, or <code>null</code>. + * @since 2.0 + */ + public String getType() { + return type; + } + + public boolean isPack200Supported() { + return supportsPack200; + } + + /** + * Resolve the model object. + * Any URL strings in the model are resolved relative to the + * base URL argument. Any translatable strings in the model that are + * specified as translation keys are localized using the supplied + * resource bundle. + * + * @param base URL + * @param bundleURL resource bundle URL + * @exception MalformedURLException + * @since 2.0 + */ + public void resolve(URL base, URL bundleURL) throws MalformedURLException { + + // Archives and feature are relative to location URL + // if the Site element has a URL tag: see spec + // locationURL = resolveURL(base, bundleURL, getLocationURLString()); + // if (locationURL == null) + // locationURL = base; + // resolveListReference(getFeatureReferenceModels(), locationURL, bundleURL); + // resolveListReference(getArchiveReferenceModels(), locationURL, bundleURL); + // + // resolveReference(getDescriptionModel(), base, bundleURL); + // resolveListReference(getCategoryModels(), base, bundleURL); + // + // URL url = resolveURL(base, bundleURL, mirrorsURLString); + // if (url != null) + // mirrorsURLString = url.toString(); + // + // if ((this instanceof ExtendedSite) && ((ExtendedSite) this).isDigestExist()) { + // ExtendedSite extendedSite = (ExtendedSite) this; + // extendedSite.setLiteFeatures(UpdateManagerUtils.getLightFeatures(extendedSite)); + // } + } + + /** + * Sets the site description. + * + * @param description site description + * @since 2.0 + */ + public void setDescription(URLEntry description) { + this.description = description; + } + + /** + * Sets the unresolved URL for the site. + * + * @param locationURLString url for the site (as a string) + * @since 2.0 + */ + public void setLocationURLString(String locationURLString) { + this.locationURLString = locationURLString; + } + + /** + * Sets additional mirror sites + * + * @param mirrors additional update site mirrors + * @since 3.1 + */ + public void setMirrors(URLEntry[] mirrors) { + doSetMirrorSiteEntryModels(mirrors); + } + + /** + * Sets the mirrors url. Mirror sites will then be obtained from this mirror url later. + * This method is complementary to setMirrorsiteEntryModels(), and only one of these + * methods should be called. + * + * @param mirrorsURL additional update site mirrors + * @since 3.1 + */ + public void setMirrorsURLString(String mirrorsURL) { + this.mirrorsURLString = mirrorsURL; + } + + public void setSupportsPack200(boolean value) { + this.supportsPack200 = value; + } + + /** + * Sets the site type. + * Throws a runtime exception if this object is marked read-only. + * + * @param type site type + * @since 2.0 + */ + public void setType(String type) { + this.type = type; + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/URLEntry.java b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/URLEntry.java new file mode 100644 index 000000000..343222328 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/URLEntry.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +package org.eclipse.equinox.internal.p2.publisher.features; + +public class URLEntry { + private String annotation; + private String url; + + public URLEntry() { + } + + public URLEntry(String url, String annotation) { + this.url = url; + this.annotation = annotation; + } + + public void setAnnotation(String annotation) { + this.annotation = annotation; + } + + public String getAnnotation() { + return annotation; + } + + public void setURL(String url) { + this.url = url; + } + + public String getURL() { + return url; + } +} diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/messages.properties b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/messages.properties new file mode 100644 index 000000000..052ad26c2 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/features/messages.properties @@ -0,0 +1,30 @@ +############################################################################### +# Copyright (c) 2000, 2007 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 +############################################################################### +# Install Update Core Properties File +# + +DefaultFeatureParser_IdOrVersionInvalid= Error parsing feature stream. The unique identifier or the version is null or empty for the State: \"{2}\": unique identifier=\"{0}\" version=\"{1}\". +DefaultSiteParser_NoSiteTag= Error parsing site stream. Unable to find root element \"site\" in the stream. +DefaultSiteParser_WrongParsingStack= Internal Error parsing site stream. Unexpected Parsing Stack: \"{0}\" +DefaultSiteParser_UnknownElement= Error parsing site stream. Unknown element \"{0}\" in parsing state \"{1}\". Check the validity of the XML file. +DefaultSiteParser_UnknownStartState= Internal Error parsing site stream. Unknown start state \"{0}\". +DefaultSiteParser_Missing= Error parsing site stream. The \"{0}\" tag of the element \"{1}\" is null or empty. Value is required. +DefaultSiteParser_ParsingStackBackToInitialState= Internal Error parsing site stream. Parsing stack back to Initial State. +DefaultSiteParser_ElementAlreadySet= Error parsing site stream. Element: \"{0}\" already set for the Site. +DefaultSiteParser_CategoryAlreadySet= Error parsing site stream. Element: \"{0}\": \"{1}\" already set for the Site. +DefaultSiteParser_UnknownEndState= Internal Error parsing site stream. Unknown end state \"{0}\". +DefaultSiteParser_ErrorParsing= Error Parsing site stream. Error: \"{0}\" +DefaultSiteParser_ErrorlineColumnMessage= Error Parsing site stream. Element \"{0}\" line: \"{1}\" column:\"{2}\". Error: \"{3}\". +DefaultSiteParser_ErrorParsingSite= Error Parsing site stream. +DefaultSiteParser_UnknownState= Unknown State \"{0}\". +DefaultSiteParser_InvalidXMLStream= The XML stream is not a valid default \"site.xml\" file. The root tag is not site. +DefaultSiteParser_mirrors = Error processing update site mirror. + diff --git a/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/messages.properties b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/messages.properties new file mode 100644 index 000000000..08affcbdc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.publisher/src/org/eclipse/equinox/internal/p2/publisher/messages.properties @@ -0,0 +1,23 @@ +############################################################################### +# 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 +############################################################################### +exception_errorConverting = An error occurred while generating manifest for {0}. +exception_outputStream = Unable to open output stream for {0}. +exception_errorParsingUpdateSite = Error parsing update site: {0}. +exception_stateAddition = An error has occurred while adding the bundle {0}. +exception_sourceDirectoryInvalid = Source directory is invalid: {0}. +exception_artifactRepoLocationURL = Artifact repository location is not a valid URL: {0}. +exception_artifactRepoNotWritable = Artifact repository is not writable: {0}. +exception_metadataRepoLocationURL = Metadata repository location is not a valid URL: {0}. +exception_metadataRepoNotWritable = Metadata repository not writable: {0}. +exception_baseLocationNotSpecified = Eclipse base location not specified. + +message_generatingMetadata = Generating metadata for {0}. +message_generationCompleted = Generation completed with success [{0} seconds].
\ No newline at end of file |