/******************************************************************************* * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. ******************************************************************************/ package org.eclipse.buckminster.pde.tasks; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.eclipse.buckminster.ant.tasks.VersionQualifierTask; import org.eclipse.buckminster.core.version.VersionHelper; import org.eclipse.buckminster.pde.IPDEConstants; import org.eclipse.buckminster.pde.Messages; import org.eclipse.buckminster.pde.PDEPlugin; import org.eclipse.buckminster.pde.internal.FeatureModelReader; import org.eclipse.buckminster.pde.internal.model.EditableFeatureModel; import org.eclipse.buckminster.pde.internal.model.ExternalBundleModel; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.equinox.p2.metadata.IVersionedId; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.core.plugin.IPluginBase; import org.eclipse.pde.internal.build.IBuildPropertiesConstants; import org.eclipse.pde.internal.core.bundle.BundleFragmentModel; import org.eclipse.pde.internal.core.bundle.BundlePluginModel; import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase; import org.eclipse.pde.internal.core.ifeature.IFeature; import org.eclipse.pde.internal.core.ifeature.IFeatureModel; import org.eclipse.pde.internal.core.plugin.ExternalFragmentModel; import org.eclipse.pde.internal.core.plugin.ExternalPluginModel; /** * @author Thomas Hallgren */ @SuppressWarnings("restriction") abstract class GroupConsolidator extends VersionQualifierTask implements IPDEConstants, IBuildPropertiesConstants { static void addVersion(Map<String, Version[]> versionMap, String id, String versionStr) { if (versionStr == null) return; Version version = Version.parseVersion(versionStr); Version[] arr = versionMap.get(id); if (arr == null) arr = new Version[] { version }; else { for (Version old : arr) if (old.equals(version)) return; Version[] newArr = new Version[arr.length + 1]; System.arraycopy(arr, 0, newArr, 0, arr.length); newArr[arr.length] = version; arr = newArr; } versionMap.put(id, arr); } static Version findBestVersion(Map<String, Version[]> versionMap, String id, String componentType, String refId, String vstr) throws CoreException { Version version = Version.create(vstr); if (version != null && Version.emptyVersion.equals(version)) version = null; Version candidate = null; Version[] versions = versionMap.get(refId); if (versions != null) { for (Version v : versions) { if (v == null) continue; if (version == null) { // Highest found version wins // if (candidate == null || v.compareTo(candidate) > 0) candidate = v; continue; } if (VersionHelper.equalsUnqualified(version, v)) { if (candidate == null || v.compareTo(candidate) > 0) candidate = v; } } } if (candidate == null) { String idWithoutSource = null; if (refId.endsWith(".source")) //$NON-NLS-1$ idWithoutSource = refId.substring(0, refId.length() - 7); else if (refId.endsWith(".source.feature")) //$NON-NLS-1$ idWithoutSource = refId.substring(0, refId.length() - 15) + ".feature"; //$NON-NLS-1$ if (idWithoutSource != null) candidate = findBestVersion(versionMap, id, componentType, idWithoutSource, vstr); if (candidate == null) // // Nothing found that can replace the version // candidate = version; } return candidate; } static InputStream getInput(File dirOrZip, String fileName) throws CoreException, FileNotFoundException { if (dirOrZip.isDirectory()) return new BufferedInputStream(new FileInputStream(new File(dirOrZip, fileName))); JarFile jarFile = null; try { jarFile = new JarFile(dirOrZip); JarEntry entry = jarFile.getJarEntry(fileName); if (entry == null) throw new FileNotFoundException(String.format("%s[%s]", dirOrZip, fileName)); //$NON-NLS-1$ // Closing the jarFile is hereby the responsibility of the user of // the returned InputStream // final JarFile innerJarFile = jarFile; jarFile = null; return new FilterInputStream(innerJarFile.getInputStream(entry)) { @Override public void close() throws IOException { try { super.close(); } catch (IOException e) { } innerJarFile.close(); } }; } catch (FileNotFoundException e) { throw e; } catch (Exception e) { throw BuckminsterException.fromMessage(e, NLS.bind(Messages.unable_to_read_0, dirOrZip)); } finally { if (jarFile != null) { try { jarFile.close(); } catch (IOException e) { PDEPlugin.getLogger().error(e, NLS.bind(Messages.error_while_closing_0, dirOrZip)); } } } } private final File outputFile; private final FeatureVersionSuffixGenerator suffixGenerator; private final Map<String, Version[]> pluginVersions = new HashMap<String, Version[]>(); private final Map<String, Version[]> featureVersions = new HashMap<String, Version[]>(); GroupConsolidator(File outputFile, File propertiesFile, List<File> featuresAndBundles, String qualifier, boolean generateVersionSuffix, int maxVersionSuffixLength, int significantDigits) throws CoreException { super(propertiesFile, qualifier); this.outputFile = outputFile; if (generateVersionSuffix) this.suffixGenerator = new FeatureVersionSuffixGenerator(getIntProperty(PROPERTY_GENERATED_VERSION_LENGTH, maxVersionSuffixLength), getIntProperty(PROPERTY_SIGNIFICANT_VERSION_DIGITS, significantDigits)); else this.suffixGenerator = null; for (File featureOrBundle : featuresAndBundles) { InputStream input = null; try { input = getInput(featureOrBundle, FEATURE_MANIFEST); IFeatureModel model = FeatureModelReader.readFeatureModel(input); IFeature feature = model.getFeature(); String id = feature.getId(); String version = feature.getVersion(); if (version == null) continue; int ctxQualLen = -1; if (version.indexOf('-') > 0) { IOUtils.close(input); input = getInput(featureOrBundle, FEATURE_MANIFEST); ctxQualLen = EditableFeatureModel.getContextQualifierLength(input); } if (suffixGenerator != null) suffixGenerator.addContextQualifierLength(id, ctxQualLen); addVersion(featureVersions, id, version); continue; } catch (FileNotFoundException e) { } finally { IOUtils.close(input); input = null; } try { input = getInput(featureOrBundle, BUNDLE_FILE); ExternalBundleModel model = new ExternalBundleModel(featureOrBundle); model.load(input, true); IBundlePluginModelBase bmodel = model.isFragmentModel() ? new BundleFragmentModel() : new BundlePluginModel(); bmodel.setEnabled(true); bmodel.setBundleModel(model); IPluginBase pb = bmodel.getPluginBase(); addVersion(pluginVersions, pb.getId(), pb.getVersion()); continue; } catch (FileNotFoundException e) { } finally { IOUtils.close(input); input = null; } try { input = getInput(featureOrBundle, PLUGIN_FILE); ExternalPluginModel model = new ExternalPluginModel(); model.load(input, true); IPluginBase pb = model.getPluginBase(); addVersion(pluginVersions, pb.getId(), pb.getVersion()); continue; } catch (FileNotFoundException e) { } finally { IOUtils.close(input); input = null; } try { input = getInput(featureOrBundle, FRAGMENT_FILE); ExternalFragmentModel model = new ExternalFragmentModel(); model.load(input, true); IPluginBase pb = model.getPluginBase(); addVersion(pluginVersions, pb.getId(), pb.getVersion()); continue; } catch (FileNotFoundException e) { } finally { IOUtils.close(input); } } } /** * Version suffix generation. Modeled after * {@link org.eclipse.pde.internal.build.builder.FeatureBuildScriptGenerator#generateFeatureVersionSuffix(org.eclipse.pde.internal.build.site.BuildTimeFeature buildFeature)} * * @return The generated suffix or <code>null</code> * @throws CoreException */ String generateFeatureVersionSuffix(List<IVersionedId> features, List<IVersionedId> bundles) throws CoreException { return suffixGenerator == null ? null : suffixGenerator.generateSuffix(features, bundles); } Map<String, Version[]> getFeatureVersions() { return featureVersions; } int getIntProperty(String property, int defaultValue) { int result = defaultValue; Object value = getProperties().get(property); if (value instanceof String) { try { result = Integer.parseInt((String) value); if (result < 1) // It has to be a positive integer. Use the default. result = defaultValue; } catch (NumberFormatException e) { // Leave as default value } } return result; } File getOutputFile() { return outputFile; } Map<String, Version[]> getPluginVersions() { return pluginVersions; } }