001
014
015 package com.liferay.util.ant.bnd;
016
017 import aQute.bnd.build.ProjectBuilder;
018 import aQute.bnd.differ.Baseline;
019 import aQute.bnd.differ.Baseline.BundleInfo;
020 import aQute.bnd.differ.Baseline.Info;
021 import aQute.bnd.differ.DiffPluginImpl;
022 import aQute.bnd.osgi.Builder;
023 import aQute.bnd.osgi.Constants;
024 import aQute.bnd.osgi.Jar;
025 import aQute.bnd.osgi.Resource;
026 import aQute.bnd.service.diff.Delta;
027 import aQute.bnd.service.diff.Diff;
028 import aQute.bnd.version.Version;
029
030 import com.liferay.portal.kernel.util.StringUtil;
031 import com.liferay.portal.kernel.util.Validator;
032
033 import java.io.BufferedWriter;
034 import java.io.File;
035 import java.io.FileWriter;
036 import java.io.IOException;
037 import java.io.PrintWriter;
038
039 import java.util.ArrayList;
040 import java.util.Arrays;
041 import java.util.Comparator;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.Set;
045
046 import org.apache.tools.ant.BuildException;
047 import org.apache.tools.ant.Project;
048 import org.apache.tools.ant.types.Path;
049
050
053 public class BaselineJarTask extends BaseBndTask {
054
055 @Override
056 public void addClasspath(Path classpath) {
057 _classpath = classpath;
058 }
059
060 public void setFile(File file) {
061 _file = file;
062 }
063
064 public void setOutputPath(File outputPath) {
065 _outputPath = outputPath;
066 }
067
068 public void setSourcePath(File sourcePath) {
069 _sourcePath = sourcePath;
070 }
071
072 @Override
073 public void trace(String format, Object... args) {
074 }
075
076 protected void doBaselineJar(
077 Jar jar, File output, aQute.bnd.build.Project bndProject)
078 throws Exception {
079
080 if (_reportLevelIsOff) {
081 return;
082 }
083
084 ProjectBuilder projectBuilder = new ProjectBuilder(bndProject);
085
086 Jar baselineJar = projectBuilder.getBaselineJar();
087
088 try {
089 if (baselineJar == null) {
090 String name = bndProject.getProperty(Constants.BASELINEREPO);
091
092 bndProject.deploy(name, output);
093
094 return;
095 }
096
097 Baseline baseline = new Baseline(this, _diffPluginImpl);
098
099 Set<Info> infos = baseline.baseline(jar, baselineJar, null);
100
101 if (infos.isEmpty()) {
102 return;
103 }
104
105 BundleInfo bundleInfo = baseline.getBundleInfo();
106
107 Info[] infosArray = infos.toArray(new Info[infos.size()]);
108
109 Arrays.sort(
110 infosArray, new Comparator<Info>() {
111
112 @Override
113 public int compare(Info info1, Info info2) {
114 return info1.packageName.compareTo(info2.packageName);
115 }
116
117 }
118 );
119
120 for (Info info : infosArray) {
121 String warnings = "-";
122
123 Version newerVersion = info.newerVersion;
124 Version suggestedVersion = info.suggestedVersion;
125
126 if (suggestedVersion != null) {
127 if (newerVersion.compareTo(suggestedVersion) > 0) {
128 warnings = "EXCESSIVE VERSION INCREASE";
129 }
130 else if (newerVersion.compareTo(suggestedVersion) < 0) {
131 warnings = "VERSION INCREASE REQUIRED";
132 }
133 }
134
135 Diff packageDiff = info.packageDiff;
136
137 Delta delta = packageDiff.getDelta();
138
139 if (delta == Delta.REMOVED) {
140 warnings = "PACKAGE REMOVED";
141 }
142 else if (delta == Delta.UNCHANGED) {
143 boolean newVersionSuggested = false;
144
145 if ((suggestedVersion.getMajor() !=
146 newerVersion.getMajor()) ||
147 (suggestedVersion.getMicro() !=
148 newerVersion.getMicro()) ||
149 (suggestedVersion.getMinor() !=
150 newerVersion.getMinor())) {
151
152 warnings = "VERSION INCREASE SUGGESTED";
153
154 newVersionSuggested = true;
155 }
156
157 if (!newVersionSuggested && !info.mismatch) {
158 continue;
159 }
160 }
161
162 if (_reportLevelIsStandard && warnings.equals("-")) {
163 continue;
164 }
165
166 doInfo(bundleInfo, info, warnings);
167
168 if (_reportLevelIsDiff && (delta != Delta.REMOVED)) {
169 doPackageDiff(packageDiff);
170 }
171 }
172 }
173 finally {
174 if (baselineJar != null) {
175 baselineJar.close();
176 }
177
178 if (_printWriter != null) {
179 _printWriter.close();
180 }
181
182 projectBuilder.close();
183 }
184 }
185
186 @Override
187 protected void doBeforeExecute() throws Exception {
188 super.doBeforeExecute();
189
190 File bndRootFile = getBndRootFile();
191
192 File rootDir = bndRootFile.getParentFile();
193
194 if (_classpath == null) {
195 throw new BuildException("classpath is null");
196 }
197
198 if ((_file == null) || !_file.exists() || _file.isDirectory()) {
199 if (_file != null) {
200 project.log(
201 "file is either missing or is a directory " +
202 _file.getAbsolutePath(),
203 Project.MSG_ERR);
204 }
205
206 throw new BuildException("file is invalid");
207 }
208
209 if ((_outputPath == null) || !_outputPath.exists() ||
210 !_outputPath.isDirectory()) {
211
212 if (_outputPath != null) {
213 project.log(
214 "outputPath is either missing or is not a directory " +
215 _outputPath.getAbsolutePath(),
216 Project.MSG_ERR);
217 }
218
219 throw new BuildException("outputPath is invalid");
220 }
221
222 _reportLevel = project.getProperty("baseline.jar.report.level");
223
224 _reportLevelIsDiff = Validator.equals(_reportLevel, "diff");
225 _reportLevelIsOff = Validator.equals(_reportLevel, "off");
226 _reportLevelIsPersist = Validator.equals(_reportLevel, "persist");
227 _reportLevelIsStandard = Validator.equals(_reportLevel, "standard");
228
229 if (_reportLevelIsPersist) {
230 _reportLevelIsDiff = true;
231
232 File baselineReportsDir = new File(
233 rootDir, getBaselineResportsDirName());
234
235 if (!baselineReportsDir.exists() && !baselineReportsDir.mkdir()) {
236 throw new BuildException(
237 "Unable tocreate " + baselineReportsDir.getName());
238 }
239
240 _logFile = new File(
241 baselineReportsDir, _outputPath.getName() + ".log");
242
243 if (_logFile.exists()) {
244 _logFile.delete();
245 }
246 }
247
248 if ((_sourcePath == null) || !_sourcePath.exists() ||
249 !_sourcePath.isDirectory()) {
250
251 if (_sourcePath != null) {
252 project.log(
253 "sourcePath is either missing or is not a directory " +
254 _sourcePath.getAbsolutePath(),
255 Project.MSG_ERR);
256 }
257
258 throw new BuildException("sourcePath is not set correctly");
259 }
260
261 for (String fileName : _classpath.list()) {
262 _classpathFiles.add(new File(fileName.replace('\\', '/')));
263 }
264
265 _bndDir = new File(rootDir, getBndDirName());
266
267 if (!rootDir.canWrite()) {
268 return;
269 }
270
271 File buildFile = new File(_bndDir, "build.bnd");
272
273 if (!_bndDir.exists() && !_bndDir.mkdir()) {
274 return;
275 }
276
277 if (buildFile.exists() || !_bndDir.canWrite()) {
278 return;
279 }
280
281 BufferedWriter bufferedWriter = new BufferedWriter(
282 new FileWriter(buildFile));
283
284 for (String line : _BUILD_DEFAULTS) {
285 bufferedWriter.write(line);
286 bufferedWriter.newLine();
287 }
288
289 bufferedWriter.close();
290
291 File baselineRepoDir = new File(_bndDir, "baselinerepo");
292
293 if (!baselineRepoDir.exists()) {
294 baselineRepoDir.mkdir();
295 }
296 }
297
298 protected void doDiff(Diff diff, StringBuffer sb) {
299 String output = String.format(
300 "%s%-3s %-10s %s", sb, getShortDelta(diff.getDelta()),
301 StringUtil.toLowerCase(String.valueOf(diff.getType())),
302 diff.getName());
303
304 project.log(output, Project.MSG_WARN);
305
306 if (_printWriter != null) {
307 _printWriter.println(output);
308 }
309
310 sb.append("\t");
311
312 for (Diff curDiff : diff.getChildren()) {
313 if (curDiff.getDelta() == Delta.UNCHANGED) {
314 continue;
315 }
316
317 doDiff(curDiff, sb);
318 }
319
320 sb.deleteCharAt(sb.length() - 1);
321 }
322
323 @Override
324 protected void doExecute() throws Exception {
325 aQute.bnd.build.Project bndProject = getBndProject();
326
327 Builder builder = new Builder(bndProject);
328
329 builder.setClasspath(
330 _classpathFiles.toArray(new File[_classpathFiles.size()]));
331 builder.setPedantic(isPedantic());
332 builder.setProperties(_file);
333 builder.setSourcepath(new File[] {_sourcePath});
334
335 Jar[] jars = builder.builds();
336
337
338
339 boolean taskFailed = report();
340 boolean bndFailed = report(builder);
341
342
343
344
345 if (taskFailed || bndFailed) {
346 throw new BuildException(
347 "bnd failed",
348 new org.apache.tools.ant.Location(_file.getAbsolutePath()));
349 }
350
351 for (Jar jar : jars) {
352 String bsn = jar.getName();
353
354 File outputFile = _outputPath;
355
356 String path = builder.getProperty("-output");
357
358 if (path == null) {
359 outputFile = getFile(_outputPath, bsn + ".jar");
360 }
361 else {
362 outputFile = getFile(_outputPath, path);
363 }
364
365 if (!outputFile.exists() ||
366 (outputFile.lastModified() <= jar.lastModified())) {
367
368 jar.write(outputFile);
369
370 Map<String, Resource> resources = jar.getResources();
371
372 log(
373 jar.getName() + " (" + outputFile.getName() + ") " +
374 resources.size());
375
376 doBaselineJar(jar, outputFile, bndProject);
377 }
378 else {
379 Map<String, Resource> resources = jar.getResources();
380
381 log(
382 jar.getName() + " (" + outputFile.getName() + ") " +
383 resources.size() + " (not modified)");
384 }
385
386 report();
387
388 jar.close();
389 }
390
391 builder.close();
392 }
393
394 protected void doHeader(BundleInfo bundleInfo) {
395 if (_headerPrinted) {
396 return;
397 }
398
399 _headerPrinted = true;
400
401 project.log(
402 "[Baseline Report] Mode: " + _reportLevel, Project.MSG_WARN);
403
404 if (bundleInfo.mismatch) {
405 project.log(
406 "[Baseline Warning] Bundle Version Change Recommended: " +
407 bundleInfo.suggestedVersion,
408 Project.MSG_WARN);
409 }
410
411 reportLog(
412 " ", "PACKAGE_NAME", "DELTA", "CUR_VER", "BASE_VER", "REC_VER",
413 "WARNINGS", "ATTRIBUTES");
414
415 reportLog(
416 "=", "==================================================",
417 "==========", "==========", "==========", "==========",
418 "==========", "==========");
419 }
420
421 protected void doInfo(BundleInfo bundleInfo, Info info, String warnings) {
422 doHeader(bundleInfo);
423
424 reportLog(
425 String.valueOf(info.mismatch ? '*' : ' '), info.packageName,
426 String.valueOf(info.packageDiff.getDelta()),
427 String.valueOf(info.newerVersion),
428 String.valueOf(info.olderVersion),
429 String.valueOf(
430 (info.suggestedVersion == null) ? "-" : info.suggestedVersion),
431 warnings, String.valueOf(info.attributes));
432 }
433
434 protected void doPackageDiff(Diff diff) {
435 StringBuffer sb = new StringBuffer();
436
437 sb.append("\t");
438
439 for (Diff curDiff : diff.getChildren()) {
440 if (curDiff.getDelta() == Delta.UNCHANGED) {
441 continue;
442 }
443
444 doDiff(curDiff, sb);
445 }
446 }
447
448 protected String getBaselineResportsDirName() {
449 if (_baselineResportsDirName != null) {
450 return _baselineResportsDirName;
451 }
452
453 _baselineResportsDirName = project.getProperty(
454 "baseline.jar.reports.dir.name");
455
456 if (_baselineResportsDirName == null) {
457 _baselineResportsDirName = _BASELINE_REPORTS_DIR;
458 }
459
460 return _baselineResportsDirName;
461 }
462
463 protected String getShortDelta(Delta delta) {
464 if (delta == Delta.ADDED) {
465 return "+";
466 }
467 else if (delta == Delta.CHANGED) {
468 return "~";
469 }
470 else if (delta == Delta.MAJOR) {
471 return ">";
472 }
473 else if (delta == Delta.MICRO) {
474 return "0xB5";
475 }
476 else if (delta == Delta.MINOR) {
477 return "<";
478 }
479 else if (delta == Delta.REMOVED) {
480 return "-";
481 }
482
483 String deltaString = delta.toString();
484
485 return String.valueOf(deltaString.charAt(0));
486 }
487
488 protected void reportLog(
489 String string1, String string2, String string3, String string4,
490 String string5, String string6, String string7, String string8) {
491
492 String output = String.format(
493 "%s %-50s %-10s %-10s %-10s %-10s %-10s", string1, string2, string3,
494 string4, string5, string6, string7);
495
496 project.log(output, Project.MSG_WARN);
497
498 if (_reportLevelIsPersist) {
499 try {
500 if (_printWriter == null) {
501 _logFile.createNewFile();
502
503 _printWriter = new PrintWriter(_logFile);
504 }
505
506 _printWriter.println(output);
507 }
508 catch (IOException ioe) {
509 throw new BuildException(ioe);
510 }
511 }
512 }
513
514 private static final String _BASELINE_REPORTS_DIR = "baseline-reports";
515
516 private final String[] _BUILD_DEFAULTS = new String[] {
517 "-plugin: aQute.bnd.deployer.obr.LocalOBR;name=baselinerepo;" +
518 "mode=build;local=${workspace}/.bnd/baselinerepo",
519 "-pluginpath: ${workspace}/osgi/lib/plugin/bnd-repository.jar",
520 "-baseline: ${ant.project.name}",
521 "-baselinerepo: baselinerepo", "-releaserepo: baselinerepo"
522 };
523
524 private String _baselineResportsDirName;
525 private File _bndDir;
526 private Path _classpath;
527 private List<File> _classpathFiles = new ArrayList<File>();
528 private DiffPluginImpl _diffPluginImpl = new DiffPluginImpl();
529 private File _file;
530 private boolean _headerPrinted;
531 private File _logFile;
532 private File _outputPath;
533 private PrintWriter _printWriter;
534 private String _reportLevel;
535 private boolean _reportLevelIsDiff;
536 private boolean _reportLevelIsOff = true;
537 private boolean _reportLevelIsPersist;
538 private boolean _reportLevelIsStandard;
539 private File _sourcePath;
540
541 }