blob: 4319b6b30ade466547de67488d7f695de8b222ba [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 McCulloch54229442012-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 McCullochf3173222012-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 McCulloch4482c702012-06-15 13:27:53 +000060 public Set<Info> baseline(Jar newer, Jar older, Instructions packageFilters) throws Exception {
Stuart McCullochf3173222012-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 McCulloch4482c702012-06-15 13:27:53 +000065 if (packageFilters == null)
Stuart McCullochf3173222012-06-07 21:57:32 +000066 packageFilters = new Instructions();
Stuart McCulloch4482c702012-06-15 13:27:53 +000067
Stuart McCullochf3173222012-06-07 21:57:32 +000068 return baseline(n, nExports, o, oExports, packageFilters);
69 }
70
Stuart McCulloch4482c702012-06-15 13:27:53 +000071 public Set<Info> baseline(Tree n, Parameters nExports, Tree o, Parameters oExports, Instructions packageFilters)
Stuart McCullochf3173222012-06-07 21:57:32 +000072 throws Exception {
Stuart McCulloch4482c702012-06-15 13:27:53 +000073 diff = n.diff(o);
74 Diff apiDiff = diff.get("<api>");
Stuart McCulloch54229442012-07-12 22:12:58 +000075 infos = Create.set();
Stuart McCullochf3173222012-06-07 21:57:32 +000076
Stuart McCulloch54229442012-07-12 22:12:58 +000077 bsn = getBsn(n);
78
79 newerVersion = getVersion(n);
80 olderVersion = getVersion(o);
81
82 Delta highestDelta = Delta.MICRO;
Stuart McCulloch4482c702012-06-15 13:27:53 +000083 for (Diff pdiff : apiDiff.getChildren()) {
Stuart McCullochf3173222012-06-07 21:57:32 +000084 if (pdiff.getType() != Type.PACKAGE) // Just packages
85 continue;
86
87 if (pdiff.getName().startsWith("java."))
88 continue;
89
90 if (!packageFilters.matches(pdiff.getName()))
91 continue;
92
93 final Info info = new Info();
94 infos.add(info);
95
96 info.packageDiff = pdiff;
97 info.packageName = pdiff.getName();
98 info.attributes = nExports.get(info.packageName);
Stuart McCulloch4482c702012-06-15 13:27:53 +000099 bnd.trace("attrs for %s %s", info.packageName, info.attributes);
Stuart McCullochf3173222012-06-07 21:57:32 +0000100
101 info.newerVersion = getVersion(info.attributes);
102 info.olderVersion = getVersion(oExports.get(info.packageName));
103 if (pdiff.getDelta() == Delta.UNCHANGED) {
104 info.suggestedVersion = info.olderVersion;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000105 if (!info.newerVersion.equals(info.olderVersion)) {
Stuart McCulloch54229442012-07-12 22:12:58 +0000106 info.warning += "No difference but versions are not equal";
Stuart McCullochf3173222012-06-07 21:57:32 +0000107 }
108 } else if (pdiff.getDelta() == Delta.REMOVED) {
109 info.suggestedVersion = null;
110 } else if (pdiff.getDelta() == Delta.ADDED) {
111 info.suggestedVersion = Version.ONE;
112 } else {
113 // We have an API change
114 info.suggestedVersion = bump(pdiff.getDelta(), info.olderVersion, 1, 0);
115
116 if (info.newerVersion.compareTo(info.suggestedVersion) < 0) {
117 info.mismatch = true; // our suggested version is smaller
118 // than
119 // the
120 // old version!
121
122 // We can fix some major problems by assuming
123 // that an interface is a provider interface
124 if (pdiff.getDelta() == Delta.MAJOR) {
125
126 info.providers = Create.set();
127 if (info.attributes != null)
128 info.providers.addAll(Processor.split(info.attributes
129 .get(Constants.PROVIDER_TYPE_DIRECTIVE)));
130
131 // Calculate the new delta assuming we fix all the major
132 // interfaces
133 // by making them providers
134 Delta tryDelta = pdiff.getDelta(new Ignore() {
135 public boolean contains(Diff diff) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000136 if (diff.getType() == Type.INTERFACE && diff.getDelta() == Delta.MAJOR) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000137 info.providers.add(Descriptors.getShortName(diff.getName()));
138 return true;
139 }
140 return false;
141 }
142 });
143
144 if (tryDelta != Delta.MAJOR) {
145 info.suggestedIfProviders = bump(tryDelta, info.olderVersion, 1, 0);
146 }
147 }
148 }
149 }
Stuart McCulloch54229442012-07-12 22:12:58 +0000150 if (pdiff.getDelta().compareTo(highestDelta) > 0) {
151 highestDelta = pdiff.getDelta();
152 }
153 }
154 suggestedVersion = bumpBundle(highestDelta, olderVersion, 1, 0);
155 if (suggestedVersion.getMajor() == 0) {
156 suggestedVersion = Version.ONE;
Stuart McCullochf3173222012-06-07 21:57:32 +0000157 }
158 return infos;
159 }
160
Stuart McCulloch4482c702012-06-15 13:27:53 +0000161 /**
162 * Gets the generated diff
163 *
164 * @return the diff
165 */
166 public Diff getDiff() {
167 return diff;
168 }
169
Stuart McCulloch54229442012-07-12 22:12:58 +0000170 public Set<Info> getPackageInfos() {
171 if (infos == null)
172 return Collections.emptySet();
173 return infos;
174 }
175
176 public String getBsn() {
177 return bsn;
178 }
179
180 public Version getSuggestedVersion() {
181 return suggestedVersion;
182 }
183
184 public void setSuggestedVersion(Version suggestedVersion) {
185 this.suggestedVersion = suggestedVersion;
186 }
187
188 public Version getNewerVersion() {
189 return newerVersion;
190 }
191
192 public Version getOlderVersion() {
193 return olderVersion;
194 }
195
196 public String getReleaseRepository() {
197 return releaseRepository;
198 }
199
200 public void setReleaseRepository(String releaseRepository) {
201 this.releaseRepository = releaseRepository;
202 }
203
Stuart McCullochf3173222012-06-07 21:57:32 +0000204 private Version bump(Delta delta, Version last, int offset, int base) {
205 switch (delta) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000206 case UNCHANGED :
207 return last;
208 case MINOR :
209 return new Version(last.getMajor(), last.getMinor() + offset, base);
210 case MAJOR :
211 return new Version(last.getMajor() + 1, base, base);
212 case ADDED :
213 return last;
214 default :
215 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
Stuart McCullochf3173222012-06-07 21:57:32 +0000216 }
217 }
218
Stuart McCulloch4482c702012-06-15 13:27:53 +0000219 private Version getVersion(Map<String,String> map) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000220 if (map == null)
221 return Version.LOWEST;
222
223 return Version.parseVersion(map.get(Constants.VERSION_ATTRIBUTE));
224 }
225
226 private Parameters getExports(Jar jar) throws Exception {
227 Manifest m = jar.getManifest();
228 if (m == null)
229 return new Parameters();
230
231 return OSGiHeader.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
232 }
Stuart McCulloch54229442012-07-12 22:12:58 +0000233
234 private Version getVersion(Tree top) {
235 Tree manifest = top.get("<manifest>");
236 if (manifest == null) {
237 return Version.emptyVersion;
238 }
239 for (Tree tree : manifest.getChildren()) {
240 if (tree.getName().startsWith(Constants.BUNDLE_VERSION)) {
241 return Version.parseVersion(tree.getName().substring(15));
242 }
243 }
244 return Version.emptyVersion;
245 }
Stuart McCullochf3173222012-06-07 21:57:32 +0000246
Stuart McCulloch54229442012-07-12 22:12:58 +0000247 private String getBsn(Tree top) {
248 Tree manifest = top.get("<manifest>");
249 if (manifest == null) {
250 return "";
251 }
252 for (Tree tree : manifest.getChildren()) {
253 if (tree.getName().startsWith(Constants.BUNDLE_SYMBOLICNAME) && tree.getChildren().length > 0) {
254 return tree.getChildren()[0].getName();
255 }
256 }
257 return "";
258 }
259
260 private Version bumpBundle(Delta delta, Version last, int offset, int base) {
261 switch (delta) {
262 case MINOR :
263 return new Version(last.getMajor(), last.getMinor() + offset, base);
264 case MAJOR :
265 return new Version(last.getMajor() + 1, base, base);
266 case ADDED :
267 return new Version(last.getMajor(), last.getMinor() + offset, base);
268 default :
269 return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
270 }
271 }
Stuart McCullochf3173222012-06-07 21:57:32 +0000272}