blob: cd2d9b6b5378d847bf60ea82188fceb11320f26a [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001package aQute.bnd.differ;
2
3import java.io.*;
4import java.util.*;
5import java.util.jar.*;
6
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00007import aQute.bnd.header.*;
8import aQute.bnd.osgi.*;
Stuart McCullochbb014372012-06-07 21:57:32 +00009import aQute.bnd.service.diff.*;
10import aQute.bnd.service.diff.Diff.Ignore;
Stuart McCulloch6a046662012-07-19 13:11:20 +000011import aQute.bnd.version.*;
Stuart McCullochbb014372012-06-07 21:57:32 +000012import aQute.libg.generics.*;
Stuart McCulloch81d48de2012-06-29 19:23:09 +000013import aQute.service.reporter.*;
Stuart McCullochbb014372012-06-07 21:57:32 +000014
15/**
16 * This class maintains
Stuart McCullochbb014372012-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 McCulloch2286f232012-06-15 13:27:53 +000024 public Map<String,String> attributes;
Stuart McCullochbb014372012-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 McCulloch2286f232012-06-15 13:27:53 +000030 public String warning = "";
Stuart McCullochbb014372012-06-07 21:57:32 +000031
32 }
33
34 final Differ differ;
35 final Reporter bnd;
Stuart McCulloch2286f232012-06-15 13:27:53 +000036 Diff diff;
Stuart McCulloch7adbc952012-07-12 22:12:58 +000037 Set<Info> infos;
38 String bsn;
39 Version newerVersion;
40 Version olderVersion;
41 Version suggestedVersion;
42 String releaseRepository;
Stuart McCullochbb014372012-06-07 21:57:32 +000043
44 public Baseline(Reporter bnd, Differ differ) throws IOException {
45 this.differ = differ;
46 this.bnd = bnd;
47 }
48
49 /**
50 * This method compares a jar to a baseline jar and returns version
51 * suggestions if the baseline does not agree with the newer jar. The
52 * returned set contains all the exported packages.
53 *
54 * @param newer
55 * @param older
56 * @return null if ok, otherwise a set of suggested versions for all
57 * packages (also the ones that were ok).
58 * @throws Exception
59 */
Stuart McCulloch2286f232012-06-15 13:27:53 +000060 public Set<Info> baseline(Jar newer, Jar older, Instructions packageFilters) throws Exception {
Stuart McCullochbb014372012-06-07 21:57:32 +000061 Tree n = differ.tree(newer);
62 Parameters nExports = getExports(newer);
63 Tree o = differ.tree(older);
64 Parameters oExports = getExports(older);
Stuart McCulloch2286f232012-06-15 13:27:53 +000065 if (packageFilters == null)
Stuart McCullochbb014372012-06-07 21:57:32 +000066 packageFilters = new Instructions();
Stuart McCulloch2286f232012-06-15 13:27:53 +000067
Stuart McCullochbb014372012-06-07 21:57:32 +000068 return baseline(n, nExports, o, oExports, packageFilters);
69 }
70
Stuart McCulloch2286f232012-06-15 13:27:53 +000071 public Set<Info> baseline(Tree n, Parameters nExports, Tree o, Parameters oExports, Instructions packageFilters)
Stuart McCullochbb014372012-06-07 21:57:32 +000072 throws Exception {
Stuart McCulloch2286f232012-06-15 13:27:53 +000073 diff = n.diff(o);
74 Diff apiDiff = diff.get("<api>");
Stuart McCulloch7adbc952012-07-12 22:12:58 +000075 infos = Create.set();
Stuart McCullochbb014372012-06-07 21:57:32 +000076
Stuart McCulloch7adbc952012-07-12 22:12:58 +000077 bsn = getBsn(n);
78
79 newerVersion = getVersion(n);
80 olderVersion = getVersion(o);
Stuart McCulloch3ed949e2012-10-18 20:01:21 +000081
82 boolean firstRelease = false;
83 if (o.get("<manifest>") == null) {
84 firstRelease = true;
85 if (newerVersion.equals(Version.emptyVersion)) {
86 newerVersion = Version.ONE;
87 }
88 }
Stuart McCulloch7adbc952012-07-12 22:12:58 +000089 Delta highestDelta = Delta.MICRO;
Stuart McCulloch2286f232012-06-15 13:27:53 +000090 for (Diff pdiff : apiDiff.getChildren()) {
Stuart McCullochbb014372012-06-07 21:57:32 +000091 if (pdiff.getType() != Type.PACKAGE) // Just packages
92 continue;
93
94 if (pdiff.getName().startsWith("java."))
95 continue;
96
97 if (!packageFilters.matches(pdiff.getName()))
98 continue;
99
100 final Info info = new Info();
101 infos.add(info);
102
103 info.packageDiff = pdiff;
104 info.packageName = pdiff.getName();
105 info.attributes = nExports.get(info.packageName);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000106 bnd.trace("attrs for %s %s", info.packageName, info.attributes);
Stuart McCullochbb014372012-06-07 21:57:32 +0000107
108 info.newerVersion = getVersion(info.attributes);
109 info.olderVersion = getVersion(oExports.get(info.packageName));
110 if (pdiff.getDelta() == Delta.UNCHANGED) {
111 info.suggestedVersion = info.olderVersion;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000112 if (!info.newerVersion.equals(info.olderVersion)) {
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000113 info.warning += "No difference but versions are not equal";
Stuart McCullochbb014372012-06-07 21:57:32 +0000114 }
115 } else if (pdiff.getDelta() == Delta.REMOVED) {
116 info.suggestedVersion = null;
117 } else if (pdiff.getDelta() == Delta.ADDED) {
Stuart McCulloch3ed949e2012-10-18 20:01:21 +0000118 if (firstRelease) {
119 info.suggestedVersion = info.newerVersion;
120 if (info.suggestedVersion.equals(Version.emptyVersion)) {
121 info.suggestedVersion = newerVersion.getWithoutQualifier();
122 }
123 } else {
124 info.suggestedVersion = Version.ONE;
125 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000126 } else {
127 // We have an API change
128 info.suggestedVersion = bump(pdiff.getDelta(), info.olderVersion, 1, 0);
129
130 if (info.newerVersion.compareTo(info.suggestedVersion) < 0) {
131 info.mismatch = true; // our suggested version is smaller
132 // than
133 // the
134 // old version!
135
136 // We can fix some major problems by assuming
137 // that an interface is a provider interface
138 if (pdiff.getDelta() == Delta.MAJOR) {
139
140 info.providers = Create.set();
141 if (info.attributes != null)
142 info.providers.addAll(Processor.split(info.attributes
143 .get(Constants.PROVIDER_TYPE_DIRECTIVE)));
144
145 // Calculate the new delta assuming we fix all the major
146 // interfaces
147 // by making them providers
148 Delta tryDelta = pdiff.getDelta(new Ignore() {
149 public boolean contains(Diff diff) {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000150 if (diff.getType() == Type.INTERFACE && diff.getDelta() == Delta.MAJOR) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000151 info.providers.add(Descriptors.getShortName(diff.getName()));
152 return true;
153 }
154 return false;
155 }
156 });
157
158 if (tryDelta != Delta.MAJOR) {
159 info.suggestedIfProviders = bump(tryDelta, info.olderVersion, 1, 0);
160 }
161 }
162 }
163 }
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000164 if (pdiff.getDelta().compareTo(highestDelta) > 0) {
165 highestDelta = pdiff.getDelta();
166 }
167 }
Stuart McCulloch3ed949e2012-10-18 20:01:21 +0000168 if (firstRelease) {
169 suggestedVersion = newerVersion;
170 } else {
171 suggestedVersion = bumpBundle(highestDelta, olderVersion, 1, 0);
Stuart McCullochbb014372012-06-07 21:57:32 +0000172 }
173 return infos;
174 }
175
Stuart McCulloch2286f232012-06-15 13:27:53 +0000176 /**
177 * Gets the generated diff
178 *
179 * @return the diff
180 */
181 public Diff getDiff() {
182 return diff;
183 }
184
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000185 public Set<Info> getPackageInfos() {
186 if (infos == null)
187 return Collections.emptySet();
188 return infos;
189 }
190
191 public String getBsn() {
192 return bsn;
193 }
194
195 public Version getSuggestedVersion() {
196 return suggestedVersion;
197 }
198
199 public void setSuggestedVersion(Version suggestedVersion) {
200 this.suggestedVersion = suggestedVersion;
201 }
202
203 public Version getNewerVersion() {
204 return newerVersion;
205 }
206
207 public Version getOlderVersion() {
208 return olderVersion;
209 }
210
211 public String getReleaseRepository() {
212 return releaseRepository;
213 }
214
215 public void setReleaseRepository(String releaseRepository) {
216 this.releaseRepository = releaseRepository;
217 }
218
Stuart McCullochbb014372012-06-07 21:57:32 +0000219 private Version bump(Delta delta, Version last, int offset, int base) {
220 switch (delta) {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000221 case UNCHANGED :
222 return last;
223 case MINOR :
224 return new Version(last.getMajor(), last.getMinor() + offset, base);
225 case MAJOR :
226 return new Version(last.getMajor() + 1, base, base);
227 case ADDED :
228 return last;
229 default :
230 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
Stuart McCullochbb014372012-06-07 21:57:32 +0000231 }
232 }
233
Stuart McCulloch2286f232012-06-15 13:27:53 +0000234 private Version getVersion(Map<String,String> map) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000235 if (map == null)
236 return Version.LOWEST;
237
238 return Version.parseVersion(map.get(Constants.VERSION_ATTRIBUTE));
239 }
240
241 private Parameters getExports(Jar jar) throws Exception {
242 Manifest m = jar.getManifest();
243 if (m == null)
244 return new Parameters();
245
246 return OSGiHeader.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
247 }
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000248
249 private Version getVersion(Tree top) {
250 Tree manifest = top.get("<manifest>");
251 if (manifest == null) {
252 return Version.emptyVersion;
253 }
254 for (Tree tree : manifest.getChildren()) {
255 if (tree.getName().startsWith(Constants.BUNDLE_VERSION)) {
256 return Version.parseVersion(tree.getName().substring(15));
257 }
258 }
259 return Version.emptyVersion;
260 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000261
Stuart McCulloch7adbc952012-07-12 22:12:58 +0000262 private String getBsn(Tree top) {
263 Tree manifest = top.get("<manifest>");
264 if (manifest == null) {
265 return "";
266 }
267 for (Tree tree : manifest.getChildren()) {
268 if (tree.getName().startsWith(Constants.BUNDLE_SYMBOLICNAME) && tree.getChildren().length > 0) {
269 return tree.getChildren()[0].getName();
270 }
271 }
272 return "";
273 }
274
275 private Version bumpBundle(Delta delta, Version last, int offset, int base) {
276 switch (delta) {
277 case MINOR :
278 return new Version(last.getMajor(), last.getMinor() + offset, base);
279 case MAJOR :
280 return new Version(last.getMajor() + 1, base, base);
281 case ADDED :
282 return new Version(last.getMajor(), last.getMinor() + offset, base);
283 default :
284 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
285 }
286 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000287}