package org.eclipse.buckminster.pde.tasks; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.buckminster.core.actor.IActionContext; import org.eclipse.buckminster.core.version.VersionHelper; import org.eclipse.buckminster.pde.IPDEConstants; import org.eclipse.equinox.frameworkadmin.BundleInfo; import org.eclipse.equinox.internal.p2.publisher.eclipse.IProductDescriptor; import org.eclipse.equinox.internal.p2.publisher.eclipse.ProductContentType; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.IVersionedId; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; import org.eclipse.equinox.p2.metadata.VersionedId; import org.eclipse.equinox.p2.query.IQuery; import org.eclipse.equinox.p2.query.IQueryResult; import org.eclipse.equinox.p2.query.IQueryable; import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.IRepositoryReference; /** * @author Thomas Hallgren * @author Lorenzo Bettini - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=428301 */ @SuppressWarnings("restriction") public class ProductVersionPatcher implements IProductDescriptor { private final IProductDescriptor product; private final IActionContext context; private IQueryable<IInstallableUnit> mdr; private static final String BUILD_ID_KEY = "eclipse.buildId";//$NON-NLS-1$ private static final String BUILD_ID_TAG = "@qualifier@"; //$NON-NLS-1$ public ProductVersionPatcher(IProductDescriptor product, IActionContext context) { this.product = product; this.context = context; } @Override public String getApplication() { return product.getApplication(); } @Override public List<BundleInfo> getBundleInfos() { List<BundleInfo> bis = product.getBundleInfos(); if (bis.size() == 0) return bis; List<BundleInfo> pbis = new ArrayList<BundleInfo>(bis.size()); for (BundleInfo bi : bis) { BundleInfo pbi = new BundleInfo(bi.getLocation(), bi.getStartLevel(), bi.isMarkedAsStarted()); pbi.setBaseLocation(bi.getBaseLocation()); pbi.setBundleId(bi.getBundleId()); pbi.setManifest(bi.getManifest()); pbi.setResolved(bi.isResolved()); String id = bi.getSymbolicName(); pbi.setSymbolicName(id); Version v = adjustVersion(id, bi.getVersion(), false); if (v != null) pbi.setVersion(v.toString()); pbis.add(pbi); } return pbis; } @Override public List<IVersionedId> getBundles(boolean includeFragments) { return adjustVersionedIdList(product.getBundles(includeFragments), false); } @Override public String getConfigIniPath(String os) { return product.getConfigIniPath(os); } @Override public Map<String, String> getConfigurationProperties() { Map<String, String> cprops = product.getConfigurationProperties(); cprops = addBuildIdProperties(cprops); return cprops; } private Map<String, String> addBuildIdProperties(Map<String, String> cprops) { String buildId = cprops.get(BUILD_ID_KEY); if (buildId != null && buildId.contains(BUILD_ID_TAG)) { String realBuildId = (String) context.getProperties().get("build.id"); //$NON-NLS-1$ if (realBuildId != null) { cprops = new HashMap<String, String>(cprops); cprops.put(BUILD_ID_KEY, buildId.replace(BUILD_ID_TAG, realBuildId)); } } return cprops; } @Override public List<IVersionedId> getFeatures() { return adjustVersionedIdList(product.getFeatures(), true); } @Override public List<IVersionedId> getFragments() { return adjustVersionedIdList(product.getFragments(), false); } @Override public String[] getIcons(String os) { return product.getIcons(os); } @Override public String getId() { return product.getId(); } @Override public String getLauncherName() { return product.getLauncherName(); } @Override public String getLicenseText() { return product.getLicenseText(); } @Override public String getLicenseURL() { return product.getLicenseURL(); } @Override public File getLocation() { return product.getLocation(); } @Override public ProductContentType getProductContentType() { return product.getProductContentType(); } @Override public String getProductId() { return product.getProductId(); } @Override public String getProductName() { return product.getProductName(); } @Override public String getProgramArguments(String os) { return product.getProgramArguments(os); } @Override public String getSplashLocation() { return product.getSplashLocation(); } @Override public String getVersion() { String vstr = product.getVersion(); Version version = vstr == null ? null : Version.parseVersion(vstr); if (Version.emptyVersion.equals(version)) version = null; if (version != null) { String qualifier = VersionHelper.getQualifier(version); if (qualifier == null || !qualifier.endsWith("qualifier")) //$NON-NLS-1$ return vstr; } boolean features = product.useFeatures(); List<IVersionedId> deps = features ? product.getFeatures() : product.getBundles(false); if (deps.size() == 1) { IVersionedId dep = deps.get(0); version = adjustVersion(dep.getId(), dep.getVersion(), features); if (version != null) vstr = version.toString(); } return vstr; } @Override public String getVMArguments(String os) { return product.getVMArguments(os); } @Override public boolean includeLaunchers() { return product.includeLaunchers(); } @Override public boolean useFeatures() { return product.useFeatures(); } void setQueryable(IQueryable<IInstallableUnit> queryable) { mdr = queryable; } private Version adjustVersion(String id, String version, boolean feature) { return adjustVersion(id, version == null ? null : Version.parseVersion(version), feature); } private Version adjustVersion(String id, Version version, boolean isFeature) { VersionRange range = null; if (version != null && Version.emptyVersion.equals(version)) version = null; if (version != null) { String qualifier = VersionHelper.getQualifier(version); if (qualifier == null || !qualifier.endsWith("qualifier")) //$NON-NLS-1$ return version; org.osgi.framework.Version ov = new org.osgi.framework.Version(version.toString()); if (qualifier.length() > 9) { String lowQual = qualifier.substring(0, qualifier.length() - 1); String highQual = lowQual + "zzzzzzzzzzzzzzzz"; //$NON-NLS-1$ Version low = Version.createOSGi(ov.getMajor(), ov.getMinor(), ov.getMicro(), lowQual); Version high = Version.createOSGi(ov.getMajor(), ov.getMinor(), ov.getMicro(), highQual); range = new VersionRange(low, true, high, true); } else { Version low = Version.createOSGi(ov.getMajor(), ov.getMinor(), ov.getMicro()); Version high = Version.createOSGi(ov.getMajor(), ov.getMinor(), ov.getMicro() + 1); range = new VersionRange(low, true, high, false); } } String iuID = id; if (isFeature && !iuID.endsWith(IPDEConstants.FEATURE_GROUP)) iuID += IPDEConstants.FEATURE_GROUP; IQuery<IInstallableUnit> query = QueryUtil.createIUQuery(iuID, range); IQueryResult<IInstallableUnit> result = mdr.query(query, null); if (result.isEmpty()) return version; Version candidate = null; Iterator<IInstallableUnit> itor = result.iterator(); while (itor.hasNext()) { Version v = itor.next().getVersion(); if (candidate == null || v.compareTo(candidate) > 0) candidate = v; } return candidate; } private List<IVersionedId> adjustVersionedIdList(List<IVersionedId> vns, boolean features) { int top = vns.size(); if (top == 0) return vns; ArrayList<IVersionedId> pvns = new ArrayList<IVersionedId>(top); for (IVersionedId vn : vns) { String id = vn.getId(); pvns.add(new VersionedId(id, adjustVersion(id, vn.getVersion(), features))); } return pvns; } @Override public String getVMArguments(String os, String arch) { return product.getVMArguments(os, arch); } @Override public String getProgramArguments(String os, String arch) { return product.getProgramArguments(os, arch); } @Override public Map<String, String> getConfigurationProperties(String os, String arch) { Map<String, String> cprops = product.getConfigurationProperties(os, arch); cprops = addBuildIdProperties(cprops); return cprops; } @Override public List<IRepositoryReference> getRepositoryEntries() { return product.getRepositoryEntries(); } @Override public boolean hasBundles(boolean includeFragments) { return product.hasBundles(includeFragments); } @Override public boolean hasFeatures() { return product.hasFeatures(); } @Override public List<IVersionedId> getFeatures(int options) { return product.getFeatures(options); } }