blob: b5eabb5267290f2f9c83bb942ba1f5ff2f076945 [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
Stuart McCulloch42151ee2012-07-16 13:43:38 +00007import aQute.bnd.header.*;
8import aQute.bnd.osgi.*;
Stuart McCullochf3173222012-06-07 21:57:32 +00009import aQute.bnd.service.diff.*;
10import aQute.bnd.service.diff.Diff.Ignore;
Stuart McCullochf3173222012-06-07 21:57:32 +000011import aQute.libg.generics.*;
Stuart McCulloch1a890552012-06-29 19:23:09 +000012import aQute.service.reporter.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000013
14/**
15 * This class maintains
Stuart McCullochf3173222012-06-07 21:57:32 +000016 */
17public class Baseline {
18
19 public static class Info {
20 public String packageName;
21 public Diff packageDiff;
22 public Collection<String> providers;
Stuart McCulloch4482c702012-06-15 13:27:53 +000023 public Map<String,String> attributes;
Stuart McCullochf3173222012-06-07 21:57:32 +000024 public Version newerVersion;
25 public Version olderVersion;
26 public Version suggestedVersion;
27 public Version suggestedIfProviders;
28 public boolean mismatch;
Stuart McCulloch4482c702012-06-15 13:27:53 +000029 public String warning = "";
Stuart McCullochf3173222012-06-07 21:57:32 +000030
31 }
32
33 final Differ differ;
34 final Reporter bnd;
Stuart McCulloch4482c702012-06-15 13:27:53 +000035 Diff diff;
Stuart McCulloch54229442012-07-12 22:12:58 +000036 Set<Info> infos;
37 String bsn;
38 Version newerVersion;
39 Version olderVersion;
40 Version suggestedVersion;
41 String releaseRepository;
Stuart McCullochf3173222012-06-07 21:57:32 +000042
43 public Baseline(Reporter bnd, Differ differ) throws IOException {
44 this.differ = differ;
45 this.bnd = bnd;
46 }
47
48 /**
49 * This method compares a jar to a baseline jar and returns version
50 * suggestions if the baseline does not agree with the newer jar. The
51 * returned set contains all the exported packages.
52 *
53 * @param newer
54 * @param older
55 * @return null if ok, otherwise a set of suggested versions for all
56 * packages (also the ones that were ok).
57 * @throws Exception
58 */
Stuart McCulloch4482c702012-06-15 13:27:53 +000059 public Set<Info> baseline(Jar newer, Jar older, Instructions packageFilters) throws Exception {
Stuart McCullochf3173222012-06-07 21:57:32 +000060 Tree n = differ.tree(newer);
61 Parameters nExports = getExports(newer);
62 Tree o = differ.tree(older);
63 Parameters oExports = getExports(older);
Stuart McCulloch4482c702012-06-15 13:27:53 +000064 if (packageFilters == null)
Stuart McCullochf3173222012-06-07 21:57:32 +000065 packageFilters = new Instructions();
Stuart McCulloch4482c702012-06-15 13:27:53 +000066
Stuart McCullochf3173222012-06-07 21:57:32 +000067 return baseline(n, nExports, o, oExports, packageFilters);
68 }
69
Stuart McCulloch4482c702012-06-15 13:27:53 +000070 public Set<Info> baseline(Tree n, Parameters nExports, Tree o, Parameters oExports, Instructions packageFilters)
Stuart McCullochf3173222012-06-07 21:57:32 +000071 throws Exception {
Stuart McCulloch4482c702012-06-15 13:27:53 +000072 diff = n.diff(o);
73 Diff apiDiff = diff.get("<api>");
Stuart McCulloch54229442012-07-12 22:12:58 +000074 infos = Create.set();
Stuart McCullochf3173222012-06-07 21:57:32 +000075
Stuart McCulloch54229442012-07-12 22:12:58 +000076 bsn = getBsn(n);
77
78 newerVersion = getVersion(n);
79 olderVersion = getVersion(o);
80
81 Delta highestDelta = Delta.MICRO;
Stuart McCulloch4482c702012-06-15 13:27:53 +000082 for (Diff pdiff : apiDiff.getChildren()) {
Stuart McCullochf3173222012-06-07 21:57:32 +000083 if (pdiff.getType() != Type.PACKAGE) // Just packages
84 continue;
85
86 if (pdiff.getName().startsWith("java."))
87 continue;
88
89 if (!packageFilters.matches(pdiff.getName()))
90 continue;
91
92 final Info info = new Info();
93 infos.add(info);
94
95 info.packageDiff = pdiff;
96 info.packageName = pdiff.getName();
97 info.attributes = nExports.get(info.packageName);
Stuart McCulloch4482c702012-06-15 13:27:53 +000098 bnd.trace("attrs for %s %s", info.packageName, info.attributes);
Stuart McCullochf3173222012-06-07 21:57:32 +000099
100 info.newerVersion = getVersion(info.attributes);
101 info.olderVersion = getVersion(oExports.get(info.packageName));
102 if (pdiff.getDelta() == Delta.UNCHANGED) {
103 info.suggestedVersion = info.olderVersion;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000104 if (!info.newerVersion.equals(info.olderVersion)) {
Stuart McCulloch54229442012-07-12 22:12:58 +0000105 info.warning += "No difference but versions are not equal";
Stuart McCullochf3173222012-06-07 21:57:32 +0000106 }
107 } else if (pdiff.getDelta() == Delta.REMOVED) {
108 info.suggestedVersion = null;
109 } else if (pdiff.getDelta() == Delta.ADDED) {
110 info.suggestedVersion = Version.ONE;
111 } else {
112 // We have an API change
113 info.suggestedVersion = bump(pdiff.getDelta(), info.olderVersion, 1, 0);
114
115 if (info.newerVersion.compareTo(info.suggestedVersion) < 0) {
116 info.mismatch = true; // our suggested version is smaller
117 // than
118 // the
119 // old version!
120
121 // We can fix some major problems by assuming
122 // that an interface is a provider interface
123 if (pdiff.getDelta() == Delta.MAJOR) {
124
125 info.providers = Create.set();
126 if (info.attributes != null)
127 info.providers.addAll(Processor.split(info.attributes
128 .get(Constants.PROVIDER_TYPE_DIRECTIVE)));
129
130 // Calculate the new delta assuming we fix all the major
131 // interfaces
132 // by making them providers
133 Delta tryDelta = pdiff.getDelta(new Ignore() {
134 public boolean contains(Diff diff) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000135 if (diff.getType() == Type.INTERFACE && diff.getDelta() == Delta.MAJOR) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000136 info.providers.add(Descriptors.getShortName(diff.getName()));
137 return true;
138 }
139 return false;
140 }
141 });
142
143 if (tryDelta != Delta.MAJOR) {
144 info.suggestedIfProviders = bump(tryDelta, info.olderVersion, 1, 0);
145 }
146 }
147 }
148 }
Stuart McCulloch54229442012-07-12 22:12:58 +0000149 if (pdiff.getDelta().compareTo(highestDelta) > 0) {
150 highestDelta = pdiff.getDelta();
151 }
152 }
153 suggestedVersion = bumpBundle(highestDelta, olderVersion, 1, 0);
154 if (suggestedVersion.getMajor() == 0) {
155 suggestedVersion = Version.ONE;
Stuart McCullochf3173222012-06-07 21:57:32 +0000156 }
157 return infos;
158 }
159
Stuart McCulloch4482c702012-06-15 13:27:53 +0000160 /**
161 * Gets the generated diff
162 *
163 * @return the diff
164 */
165 public Diff getDiff() {
166 return diff;
167 }
168
Stuart McCulloch54229442012-07-12 22:12:58 +0000169 public Set<Info> getPackageInfos() {
170 if (infos == null)
171 return Collections.emptySet();
172 return infos;
173 }
174
175 public String getBsn() {
176 return bsn;
177 }
178
179 public Version getSuggestedVersion() {
180 return suggestedVersion;
181 }
182
183 public void setSuggestedVersion(Version suggestedVersion) {
184 this.suggestedVersion = suggestedVersion;
185 }
186
187 public Version getNewerVersion() {
188 return newerVersion;
189 }
190
191 public Version getOlderVersion() {
192 return olderVersion;
193 }
194
195 public String getReleaseRepository() {
196 return releaseRepository;
197 }
198
199 public void setReleaseRepository(String releaseRepository) {
200 this.releaseRepository = releaseRepository;
201 }
202
Stuart McCullochf3173222012-06-07 21:57:32 +0000203 private Version bump(Delta delta, Version last, int offset, int base) {
204 switch (delta) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000205 case UNCHANGED :
206 return last;
207 case MINOR :
208 return new Version(last.getMajor(), last.getMinor() + offset, base);
209 case MAJOR :
210 return new Version(last.getMajor() + 1, base, base);
211 case ADDED :
212 return last;
213 default :
214 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
Stuart McCullochf3173222012-06-07 21:57:32 +0000215 }
216 }
217
Stuart McCulloch4482c702012-06-15 13:27:53 +0000218 private Version getVersion(Map<String,String> map) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000219 if (map == null)
220 return Version.LOWEST;
221
222 return Version.parseVersion(map.get(Constants.VERSION_ATTRIBUTE));
223 }
224
225 private Parameters getExports(Jar jar) throws Exception {
226 Manifest m = jar.getManifest();
227 if (m == null)
228 return new Parameters();
229
230 return OSGiHeader.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
231 }
Stuart McCulloch54229442012-07-12 22:12:58 +0000232
233 private Version getVersion(Tree top) {
234 Tree manifest = top.get("<manifest>");
235 if (manifest == null) {
236 return Version.emptyVersion;
237 }
238 for (Tree tree : manifest.getChildren()) {
239 if (tree.getName().startsWith(Constants.BUNDLE_VERSION)) {
240 return Version.parseVersion(tree.getName().substring(15));
241 }
242 }
243 return Version.emptyVersion;
244 }
Stuart McCullochf3173222012-06-07 21:57:32 +0000245
Stuart McCulloch54229442012-07-12 22:12:58 +0000246 private String getBsn(Tree top) {
247 Tree manifest = top.get("<manifest>");
248 if (manifest == null) {
249 return "";
250 }
251 for (Tree tree : manifest.getChildren()) {
252 if (tree.getName().startsWith(Constants.BUNDLE_SYMBOLICNAME) && tree.getChildren().length > 0) {
253 return tree.getChildren()[0].getName();
254 }
255 }
256 return "";
257 }
258
259 private Version bumpBundle(Delta delta, Version last, int offset, int base) {
260 switch (delta) {
261 case MINOR :
262 return new Version(last.getMajor(), last.getMinor() + offset, base);
263 case MAJOR :
264 return new Version(last.getMajor() + 1, base, base);
265 case ADDED :
266 return new Version(last.getMajor(), last.getMinor() + offset, base);
267 default :
268 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
269 }
270 }
Stuart McCullochf3173222012-06-07 21:57:32 +0000271}