Use local copy of latest bndlib code for pre-release testing purposes

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java b/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java
new file mode 100644
index 0000000..eee3e27
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java
@@ -0,0 +1,174 @@
+package aQute.bnd.differ;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.*;
+
+import aQute.bnd.service.diff.*;
+import aQute.bnd.service.diff.Diff.Ignore;
+import aQute.lib.osgi.*;
+import aQute.libg.generics.*;
+import aQute.libg.header.*;
+import aQute.libg.reporter.*;
+import aQute.libg.version.*;
+
+/**
+ * This class maintains
+ * 
+ */
+public class Baseline {
+
+	public static class Info {
+		public String				packageName;
+		public Diff					packageDiff;
+		public Collection<String>	providers;
+		public Map<String, String>	attributes;
+		public Version				newerVersion;
+		public Version				olderVersion;
+		public Version				suggestedVersion;
+		public Version				suggestedIfProviders;
+		public boolean				mismatch;
+		public String				warning="";
+
+	}
+
+	final Differ	differ;
+	final Reporter	bnd;
+
+	public Baseline(Reporter bnd, Differ differ) throws IOException {
+		this.differ = differ;
+		this.bnd = bnd;
+	}
+
+	/**
+	 * This method compares a jar to a baseline jar and returns version
+	 * suggestions if the baseline does not agree with the newer jar. The
+	 * returned set contains all the exported packages.
+	 * 
+	 * @param newer
+	 * @param older
+	 * @return null if ok, otherwise a set of suggested versions for all
+	 *         packages (also the ones that were ok).
+	 * @throws Exception
+	 */
+	public Set<Info> baseline(Jar newer, Jar older, Instructions packageFilters)
+			throws Exception {
+		Tree n = differ.tree(newer);
+		Parameters nExports = getExports(newer);
+		Tree o = differ.tree(older);
+		Parameters oExports = getExports(older);
+		if ( packageFilters == null)
+			packageFilters = new Instructions();
+		
+		return baseline(n, nExports, o, oExports, packageFilters);
+	}
+
+	public Set<Info> baseline(Tree n, Parameters nExports, Tree o,
+			Parameters oExports, Instructions packageFilters)
+			throws Exception {
+		Diff diff = n.diff(o).get("<api>");
+		Set<Info> infos = Create.set();
+
+		for (Diff pdiff : diff.getChildren()) {
+			if (pdiff.getType() != Type.PACKAGE) // Just packages
+				continue;
+
+			if (pdiff.getName().startsWith("java."))
+				continue;
+
+			if (!packageFilters.matches(pdiff.getName()))
+				continue;
+
+			final Info info = new Info();
+			infos.add(info);
+
+			info.packageDiff = pdiff;
+			info.packageName = pdiff.getName();
+			info.attributes = nExports.get(info.packageName);
+			bnd.trace("attrs for %s %s", info.packageName,info.attributes);
+
+			info.newerVersion = getVersion(info.attributes);
+			info.olderVersion = getVersion(oExports.get(info.packageName));
+			if (pdiff.getDelta() == Delta.UNCHANGED) {
+				info.suggestedVersion = info.olderVersion;
+				if( !info.newerVersion.equals(info.olderVersion)) {
+					info.warning += "No difference but versions are equal";
+				}
+			} else if (pdiff.getDelta() == Delta.REMOVED) {
+				info.suggestedVersion = null;
+			} else if (pdiff.getDelta() == Delta.ADDED) {
+				info.suggestedVersion = Version.ONE;
+			} else {
+				// We have an API change
+				info.suggestedVersion = bump(pdiff.getDelta(), info.olderVersion, 1, 0);
+
+				if (info.newerVersion.compareTo(info.suggestedVersion) < 0) {
+					info.mismatch = true; // our suggested version is smaller
+											// than
+											// the
+											// old version!
+
+					// We can fix some major problems by assuming
+					// that an interface is a provider interface
+					if (pdiff.getDelta() == Delta.MAJOR) {
+
+						info.providers = Create.set();
+						if (info.attributes != null)
+							info.providers.addAll(Processor.split(info.attributes
+									.get(Constants.PROVIDER_TYPE_DIRECTIVE)));
+
+						// Calculate the new delta assuming we fix all the major
+						// interfaces
+						// by making them providers
+						Delta tryDelta = pdiff.getDelta(new Ignore() {
+							public boolean contains(Diff diff) {
+								if (diff.getType() == Type.INTERFACE
+										&& diff.getDelta() == Delta.MAJOR) {
+									info.providers.add(Descriptors.getShortName(diff.getName()));
+									return true;
+								}
+								return false;
+							}
+						});
+
+						if (tryDelta != Delta.MAJOR) {
+							info.suggestedIfProviders = bump(tryDelta, info.olderVersion, 1, 0);
+						}
+					}
+				}
+			}
+		}
+		return infos;
+	}
+
+	private Version bump(Delta delta, Version last, int offset, int base) {
+		switch (delta) {
+		case UNCHANGED:
+			return last;
+		case MINOR:
+			return new Version(last.getMajor(), last.getMinor() + offset, base);
+		case MAJOR:
+			return new Version(last.getMajor() + 1, base, base);
+		case ADDED:
+			return last;
+		default:
+			return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
+		}
+	}
+
+	private Version getVersion(Map<String, String> map) {
+		if (map == null)
+			return Version.LOWEST;
+
+		return Version.parseVersion(map.get(Constants.VERSION_ATTRIBUTE));
+	}
+
+	private Parameters getExports(Jar jar) throws Exception {
+		Manifest m = jar.getManifest();
+		if (m == null)
+			return new Parameters();
+
+		return OSGiHeader.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
+	}
+
+}