/* @generated */ /** * This class is mostly a copy of methods from * https://github.com/bndtools/bnd/blob/2.4.1.REL/biz.aQute.bndlib/src/aQute/bnd/build/ProjectBuilder.java * with small adaptations. As such it is licensed under the terms of it's * project. */ package com.liferay.ant.bnd; import aQute.bnd.header.Attrs; import aQute.bnd.osgi.Analyzer; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Instruction; import aQute.bnd.osgi.Instructions; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.Verifier; import aQute.bnd.service.RepositoryPlugin; import aQute.bnd.service.repository.InfoRepository; import aQute.bnd.service.repository.Phase; import aQute.bnd.service.repository.SearchableRepository.ResourceDescriptor; import aQute.bnd.version.Version; import aQute.lib.collections.SortedList; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.SortedSet; public class BaselineProcessor extends Analyzer { /** * This method attempts to find the baseline jar for the current project. It * reads the -baseline property and treats it as instructions. These * instructions are matched against the bsns of the jars (think sub * builders!). If they match, the sub builder is selected. * <p> * The instruction can then specify the following options: * * <pre> * version : baseline version from repository * file : a file path * </pre> * * If neither is specified, the current version is used to find the highest * version (without qualifier) that is below the current version. If a * version is specified, we take the highest version with the same base * version. * <p> * Since baselining is expensive and easily generates errors you must enable * it. The easiest solution is to {@code -baseline: *}. This will match all * sub builders and will calculate the version. * * @return a Jar or null */ public Jar getBaselineJar() throws Exception { String bl = getProperty(Constants.BASELINE); if (bl == null || Constants.NONE.equals(bl)) { return null; } Instructions baselines = new Instructions(getProperty(Constants.BASELINE)); if (baselines.isEmpty()) { return null; // no baselining } RepositoryPlugin repo = getBaselineRepo(); if (repo == null) { return null; // errors reported already } String bsn = getBsn(); Version version = new Version(getVersion()); // // Loop over the instructions, first match commits. // for (Entry<Instruction,Attrs> e : baselines.entrySet()) { if (e.getKey().matches(bsn)) { Attrs attrs = e.getValue(); Version target; if (attrs.containsKey("version")) { SortedSet<Version> versions = removeStagedAndFilter(repo.versions(bsn), repo, bsn); if (versions.isEmpty()) { // We have a repo Version v = new Version(getVersion()); if (v.getWithoutQualifier().compareTo(Version.ONE) > 0) { warning("There is no baseline for %s in the baseline repo %s. The build is for version %s, which is <= 1.0.0 which suggests that there should be a prior version.", getBsn(), repo, v); } return null; } // Specified version! String v = attrs.get("version"); if (!Verifier.isVersion(v)) { error("Not a valid version in %s %s", Constants.BASELINE, v); return null; } Version base = new Version(v); SortedSet<Version> later = versions.tailSet(base); if (later.isEmpty()) { error("For baselineing %s-%s, specified version %s not found", bsn, version, base); return null; } // First element is equal or next to the base we desire target = later.first(); // Now, we could end up with a higher version than our // current // project } else if (attrs.containsKey("file")) { // Can be useful to specify a file // for example when copying a bundle with a public api File f = getFile(attrs.get("file")); if (f != null && f.isFile()) { Jar jar = new Jar(f); addClose(jar); return jar; } error("Specified file for baseline but could not find it %s", f); return null; } else { throw new IllegalArgumentException("Instruction must contain the version or file attribute!"); } // Fetch the revision if (target.getWithoutQualifier().compareTo(version.getWithoutQualifier()) > 0) { error("The baseline version %s is higher than the current version %s for %s in %s", target, version, bsn, repo); return null; } if (target.getWithoutQualifier().compareTo(version.getWithoutQualifier()) == 0) { if (isPedantic()) { warning("Baselining against jar"); } } File file = repo.get(bsn, target, attrs); if (file == null || !file.isFile()) { error("Decided on version %s-%s but cannot get file from repo %s", bsn, version, repo); return null; } Jar jar = new Jar(file); addClose(jar); return jar; } } // Ignore, nothing matched return null; } private RepositoryPlugin getBaselineRepo() { String repoName = getProperty(Constants.BASELINEREPO); if (repoName == null) { return getReleaseRepo(); } List<RepositoryPlugin> repos = getPlugins(RepositoryPlugin.class); for (RepositoryPlugin r : repos) { if (r.getName().equals(repoName)) { return r; } } error("Could not find -baselinerepo %s", repoName); return null; } private RepositoryPlugin getReleaseRepo() { String repoName = getProperty(Constants.RELEASEREPO); List<RepositoryPlugin> repos = getPlugins(RepositoryPlugin.class); for (RepositoryPlugin r : repos) { if (r.canWrite()) { if (repoName == null || r.getName().equals(repoName)) { return r; } } } if (repoName == null) { error("Could not find a writable repo for the release repo (-releaserepo is not set)"); } else { error("No such -releaserepo %s found", repoName); } return null; } /** * Check if we have a master phase. * * @param repo * @param bsn * @param v * @return * @throws Exception */ private boolean isMaster(InfoRepository repo, String bsn, Version v) throws Exception { ResourceDescriptor descriptor = repo.getDescriptor(bsn, v); if (descriptor == null) { return false; } return descriptor.phase == Phase.MASTER; } /** * Remove any staging versions that have a variant with a higher qualifier. * * @param versions * @param repo * @return * @throws Exception */ private SortedSet<Version> removeStagedAndFilter(SortedSet<Version> versions, RepositoryPlugin repo, String bsn) throws Exception { List<Version> filtered = new ArrayList<Version>(versions); Collections.reverse(filtered); InfoRepository ir = (repo instanceof InfoRepository) ? (InfoRepository) repo : null; // // Filter any versions that only differ in qualifier // The last variable is the last one added. Since we are // sorted from high to low, we skip any earlier base versions // Version last = null; for (Iterator<Version> i = filtered.iterator(); i.hasNext();) { Version v = i.next(); // Check if same base version as last Version current = v.getWithoutQualifier(); if (last != null && current.equals(last)) { i.remove(); continue; } // // Check if this is not a master if the repo // has a state for each resource // / if (ir != null && !isMaster(ir, bsn, v)) { i.remove(); } last = current; } SortedList<Version> set = new SortedList<Version>(filtered); trace("filtered for only latest staged: %s from %s in range ", set, versions); return set; } }