/******************************************************************************* * 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.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.eclipse.buckminster.core.actor.AbstractActor; import org.eclipse.buckminster.core.actor.IActionContext; import org.eclipse.buckminster.core.cspec.IComponentIdentifier; import org.eclipse.buckminster.core.cspec.IGroup; import org.eclipse.buckminster.core.cspec.IPrerequisite; import org.eclipse.buckminster.core.cspec.model.Attribute; import org.eclipse.buckminster.core.cspec.model.CSpec; import org.eclipse.buckminster.core.cspec.model.ComponentIdentifier; import org.eclipse.buckminster.core.ctype.IComponentType; import org.eclipse.buckminster.core.version.VersionHelper; import org.eclipse.buckminster.pde.IPDEConstants; import org.eclipse.buckminster.pde.internal.FeatureModelReader; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.sax.Utils; import org.eclipse.core.runtime.CoreException; import org.eclipse.equinox.internal.p2.updatesite.SiteCategory; import org.eclipse.equinox.internal.p2.updatesite.SiteFeature; import org.eclipse.equinox.internal.p2.updatesite.SiteModel; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.pde.internal.core.ifeature.IFeature; import org.eclipse.pde.internal.core.ifeature.IFeatureModel; import org.xml.sax.SAXException; /** * <p> * This class can perform two tasks. * </p> * <ul> * <li>Create a site.xml style file based on the list of features, a template, * and the {@link CSpec} of the current {@link IActionContext}.</li> * <li>Calculate the version qualifier of the feature and assign it to a * property. The version is fetched from the {@link CSpec} of the current * {@link IActionContext} and if it ends with "qualifier" normal * qualifier replacement algorithms take place.</li> * </ul> * * @author Thomas Hallgren */ @SuppressWarnings("restriction") public class UpdateSiteGenerator extends VersionConsolidator { private static boolean categoryExists(SiteCategory[] categories, String categoryName) { int idx = categories.length; while (--idx >= 0) if (categories[idx].getName().equals(categoryName)) return true; return false; } private final List<File> features; private final IActionContext actionContext; private final SaxableSite saxableSite; public UpdateSiteGenerator(List<File> features, File template, File outputFile, File propertiesFile, String qualifier) throws CoreException, IOException { super(outputFile, propertiesFile, qualifier); this.features = features; this.actionContext = AbstractActor.getActiveContext(); if (template != null) this.saxableSite = new SaxableSite(SiteReader.getSite(template)); else this.saxableSite = new SaxableSite(new SiteModel()); } public Version run(boolean generateQualifier) throws CoreException { OutputStream output = null; try { CSpec cspec = actionContext.getCSpec(); ArrayList<ComponentIdentifier> deps = null; if (generateQualifier) deps = new ArrayList<ComponentIdentifier>(); File outputFile = getOutputFile(); if (outputFile != null) output = new BufferedOutputStream(new FileOutputStream(outputFile)); else if (!generateQualifier) // // Nothing left to do // return null; for (File file : features) { String leafName = file.getName(); if (!leafName.endsWith(".jar")) //$NON-NLS-1$ continue; JarFile jarFile = null; try { jarFile = new JarFile(file); JarEntry entry = jarFile.getJarEntry(IPDEConstants.FEATURE_MANIFEST); if (entry == null) continue; IFeatureModel model = FeatureModelReader.readFeatureModel(jarFile.getInputStream(entry)); IFeature feature = model.getFeature(); if (outputFile != null) generateFromFeature(cspec, file, feature); if (generateQualifier) deps.add(new ComponentIdentifier(feature.getId(), IComponentType.ECLIPSE_FEATURE, Version.create(feature.getVersion()))); } finally { if (jarFile != null) jarFile.close(); } } if (outputFile != null) Utils.serialize(saxableSite, output); IComponentIdentifier ci = cspec.getComponentIdentifier(); return generateQualifier ? replaceQualifier(cspec.getComponentIdentifier(), deps) : ci.getVersion(); } catch (IOException e) { throw BuckminsterException.wrap(e); } catch (SAXException e) { throw BuckminsterException.wrap(e); } finally { IOUtils.close(output); } } private void generateFromFeature(CSpec cspec, File file, IFeature feature) throws CoreException { String featureName = feature.getId(); StringBuilder urlBuilder = new StringBuilder(IPDEConstants.FEATURES_FOLDER); urlBuilder.append('/'); urlBuilder.append(file.getName()); // --We look for a category for the feature in two ways. // // First we check if an entry that matches the feature by name and // unqualified version // exists in the template. If it does, we use that entry // Version ver = Version.parseVersion(feature.getVersion()); SiteModel site = saxableSite.getSite(); SiteFeature model = null; for (SiteFeature oldModel : site.getFeatures()) { if (featureName.equals(oldModel.getFeatureIdentifier())) { Version oldVer = Version.create(oldModel.getFeatureVersion()); if (VersionHelper.equalsUnqualified(ver, oldVer)) { model = oldModel; break; } } } // When no entry was found, we check the cspec to see if the feature is // represented // in a group that maps to a category of the feature template // if (model == null) { SiteCategory[] categories = site.getCategories(); Collection<Attribute> attributes = cspec.getAttributes().values(); model = new SiteFeature(); model.setFeatureIdentifier(featureName); for (Attribute attr : attributes) { if (!(attr instanceof IGroup)) continue; String categoryName = attr.getName(); if (!categoryExists(categories, attr.getName())) continue; for (IPrerequisite included : attr.getPrerequisites()) { if (!featureName.equals(included.getComponentName())) continue; model.addCategoryName(categoryName); break; } } site.addFeature(model); } model.setURLString(urlBuilder.toString()); model.setFeatureVersion(ver.toString()); model.setSiteModel(site); } }