blob: fd27e418787f5d97a50a21ef7f3cfe63c915a222 [file] [log] [blame]
Stuart McCullochf3173222012-06-07 21:57:32 +00001package aQute.bnd.differ;
2
3import java.io.*;
4import java.util.*;
5import java.util.jar.*;
6
7import aQute.bnd.service.diff.*;
8import aQute.bnd.service.diff.Diff.Ignore;
9import aQute.lib.osgi.*;
10import aQute.libg.generics.*;
11import aQute.libg.header.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000012import aQute.libg.version.*;
Stuart McCulloch1a890552012-06-29 19:23:09 +000013import aQute.service.reporter.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000014
15/**
16 * This class maintains
Stuart McCullochf3173222012-06-07 21:57:32 +000017 */
18public class Baseline {
19
20 public static class Info {
21 public String packageName;
22 public Diff packageDiff;
23 public Collection<String> providers;
Stuart McCulloch4482c702012-06-15 13:27:53 +000024 public Map<String,String> attributes;
Stuart McCullochf3173222012-06-07 21:57:32 +000025 public Version newerVersion;
26 public Version olderVersion;
27 public Version suggestedVersion;
28 public Version suggestedIfProviders;
29 public boolean mismatch;
Stuart McCulloch4482c702012-06-15 13:27:53 +000030 public String warning = "";
Stuart McCullochf3173222012-06-07 21:57:32 +000031
32 }
33
34 final Differ differ;
35 final Reporter bnd;
Stuart McCulloch4482c702012-06-15 13:27:53 +000036 Diff diff;
Stuart McCullochf3173222012-06-07 21:57:32 +000037
38 public Baseline(Reporter bnd, Differ differ) throws IOException {
39 this.differ = differ;
40 this.bnd = bnd;
41 }
42
43 /**
44 * This method compares a jar to a baseline jar and returns version
45 * suggestions if the baseline does not agree with the newer jar. The
46 * returned set contains all the exported packages.
47 *
48 * @param newer
49 * @param older
50 * @return null if ok, otherwise a set of suggested versions for all
51 * packages (also the ones that were ok).
52 * @throws Exception
53 */
Stuart McCulloch4482c702012-06-15 13:27:53 +000054 public Set<Info> baseline(Jar newer, Jar older, Instructions packageFilters) throws Exception {
Stuart McCullochf3173222012-06-07 21:57:32 +000055 Tree n = differ.tree(newer);
56 Parameters nExports = getExports(newer);
57 Tree o = differ.tree(older);
58 Parameters oExports = getExports(older);
Stuart McCulloch4482c702012-06-15 13:27:53 +000059 if (packageFilters == null)
Stuart McCullochf3173222012-06-07 21:57:32 +000060 packageFilters = new Instructions();
Stuart McCulloch4482c702012-06-15 13:27:53 +000061
Stuart McCullochf3173222012-06-07 21:57:32 +000062 return baseline(n, nExports, o, oExports, packageFilters);
63 }
64
Stuart McCulloch4482c702012-06-15 13:27:53 +000065 public Set<Info> baseline(Tree n, Parameters nExports, Tree o, Parameters oExports, Instructions packageFilters)
Stuart McCullochf3173222012-06-07 21:57:32 +000066 throws Exception {
Stuart McCulloch4482c702012-06-15 13:27:53 +000067 diff = n.diff(o);
68 Diff apiDiff = diff.get("<api>");
Stuart McCullochf3173222012-06-07 21:57:32 +000069 Set<Info> infos = Create.set();
70
Stuart McCulloch4482c702012-06-15 13:27:53 +000071 for (Diff pdiff : apiDiff.getChildren()) {
Stuart McCullochf3173222012-06-07 21:57:32 +000072 if (pdiff.getType() != Type.PACKAGE) // Just packages
73 continue;
74
75 if (pdiff.getName().startsWith("java."))
76 continue;
77
78 if (!packageFilters.matches(pdiff.getName()))
79 continue;
80
81 final Info info = new Info();
82 infos.add(info);
83
84 info.packageDiff = pdiff;
85 info.packageName = pdiff.getName();
86 info.attributes = nExports.get(info.packageName);
Stuart McCulloch4482c702012-06-15 13:27:53 +000087 bnd.trace("attrs for %s %s", info.packageName, info.attributes);
Stuart McCullochf3173222012-06-07 21:57:32 +000088
89 info.newerVersion = getVersion(info.attributes);
90 info.olderVersion = getVersion(oExports.get(info.packageName));
91 if (pdiff.getDelta() == Delta.UNCHANGED) {
92 info.suggestedVersion = info.olderVersion;
Stuart McCulloch4482c702012-06-15 13:27:53 +000093 if (!info.newerVersion.equals(info.olderVersion)) {
Stuart McCullochf3173222012-06-07 21:57:32 +000094 info.warning += "No difference but versions are equal";
95 }
96 } else if (pdiff.getDelta() == Delta.REMOVED) {
97 info.suggestedVersion = null;
98 } else if (pdiff.getDelta() == Delta.ADDED) {
99 info.suggestedVersion = Version.ONE;
100 } else {
101 // We have an API change
102 info.suggestedVersion = bump(pdiff.getDelta(), info.olderVersion, 1, 0);
103
104 if (info.newerVersion.compareTo(info.suggestedVersion) < 0) {
105 info.mismatch = true; // our suggested version is smaller
106 // than
107 // the
108 // old version!
109
110 // We can fix some major problems by assuming
111 // that an interface is a provider interface
112 if (pdiff.getDelta() == Delta.MAJOR) {
113
114 info.providers = Create.set();
115 if (info.attributes != null)
116 info.providers.addAll(Processor.split(info.attributes
117 .get(Constants.PROVIDER_TYPE_DIRECTIVE)));
118
119 // Calculate the new delta assuming we fix all the major
120 // interfaces
121 // by making them providers
122 Delta tryDelta = pdiff.getDelta(new Ignore() {
123 public boolean contains(Diff diff) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000124 if (diff.getType() == Type.INTERFACE && diff.getDelta() == Delta.MAJOR) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000125 info.providers.add(Descriptors.getShortName(diff.getName()));
126 return true;
127 }
128 return false;
129 }
130 });
131
132 if (tryDelta != Delta.MAJOR) {
133 info.suggestedIfProviders = bump(tryDelta, info.olderVersion, 1, 0);
134 }
135 }
136 }
137 }
138 }
139 return infos;
140 }
141
Stuart McCulloch4482c702012-06-15 13:27:53 +0000142 /**
143 * Gets the generated diff
144 *
145 * @return the diff
146 */
147 public Diff getDiff() {
148 return diff;
149 }
150
Stuart McCullochf3173222012-06-07 21:57:32 +0000151 private Version bump(Delta delta, Version last, int offset, int base) {
152 switch (delta) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000153 case UNCHANGED :
154 return last;
155 case MINOR :
156 return new Version(last.getMajor(), last.getMinor() + offset, base);
157 case MAJOR :
158 return new Version(last.getMajor() + 1, base, base);
159 case ADDED :
160 return last;
161 default :
162 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
Stuart McCullochf3173222012-06-07 21:57:32 +0000163 }
164 }
165
Stuart McCulloch4482c702012-06-15 13:27:53 +0000166 private Version getVersion(Map<String,String> map) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000167 if (map == null)
168 return Version.LOWEST;
169
170 return Version.parseVersion(map.get(Constants.VERSION_ATTRIBUTE));
171 }
172
173 private Parameters getExports(Jar jar) throws Exception {
174 Manifest m = jar.getManifest();
175 if (m == null)
176 return new Parameters();
177
178 return OSGiHeader.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
179 }
180
181}