package aQute.bnd.repository.maven.provider; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import aQute.bnd.header.Parameters; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Domain; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.Processor; import aQute.bnd.osgi.Resource; import aQute.bnd.version.Version; import aQute.lib.fileset.FileSet; import aQute.lib.io.IO; import aQute.lib.strings.Strings; import aQute.lib.tag.Tag; import aQute.lib.utf8properties.UTF8Properties; import aQute.libg.command.Command; public class Tool extends Processor { private static final String OSGI_OPT_SRC = "OSGI-OPT/src/"; private final File tmp; private final File sources; private final File javadoc; private final File javadocOptions; private final Domain manifest; public Tool(Processor parent, Jar jar) throws Exception { super(parent); tmp = Files.createTempDirectory("tool").toFile(); sources = new File(tmp, "sources"); javadoc = new File(tmp, "javadoc"); javadocOptions = new File(tmp, "javadoc.options"); manifest = Domain.domain(jar.getManifest()); for (Entry<String,Resource> e : jar.getResources().entrySet()) { if (e.getKey().startsWith(OSGI_OPT_SRC)) { String path = e.getKey().substring(OSGI_OPT_SRC.length()); File out = IO.getFile(sources, path); IO.mkdirs(out.getParentFile()); IO.copy(e.getValue().openInputStream(), out); } } } public boolean hasSources() { return sources.isDirectory(); } public Jar doJavadoc(Map<String,String> options, boolean exportsOnly) throws Exception { if (!hasSources()) return new Jar("javadoc"); IO.mkdirs(javadoc); List<String> args = new ArrayList<>(); args.add("-quiet"); args.add("-protected"); args.add(String.format("%s '%s'", "-d", fileName(javadoc))); args.add("-charset 'UTF-8'"); args.add(String.format("%s '%s'", "-sourcepath", fileName(sources))); Properties pp = new UTF8Properties(); pp.putAll(options); String name = manifest.getBundleName(); if (name == null) name = manifest.getBundleSymbolicName().getKey(); String version = manifest.getBundleVersion(); if (version == null) version = Version.LOWEST.toString(); String bundleDescription = manifest.getBundleDescription(); if (bundleDescription != null && !Strings.trim(bundleDescription).isEmpty()) { printOverview(name, version, bundleDescription); } set(pp, "-doctitle", name); set(pp, "-windowtitle", name); set(pp, "-header", manifest.getBundleVendor()); set(pp, "-bottom", manifest.getBundleCopyright()); set(pp, "-footer", manifest.getBundleDocURL()); args.add("-tag 'Immutable:t:\"Immutable\"'"); args.add("-tag 'ThreadSafe:t:\"ThreadSafe\"'"); args.add("-tag 'NotThreadSafe:t:\"NotThreadSafe\"'"); args.add("-tag 'GuardedBy:mf:\"Guarded By:\"'"); args.add("-tag 'security:m:\"Required Permissions\"'"); args.add("-tag 'noimplement:t:\"Consumers of this API must not implement this interface\"'"); for (Enumeration< ? > e = pp.propertyNames(); e.hasMoreElements();) { String key = (String) e.nextElement(); String value = pp.getProperty(key); if (key.startsWith("-")) { // // Allow people to add the same command multiple times // by suffixing it with '.' something // int n = key.lastIndexOf('.'); if (n > 0) { key = key.substring(0, n); } args.add(String.format("%s '%s'", key, escape(value))); } } FileSet set = new FileSet(sources, "**.java"); for (File f : set.getFiles()) { args.add(String.format("'%s'", fileName(f))); } if (exportsOnly) { Parameters exports = manifest.getExportPackage(); for (String packageName : exports.keySet()) { args.add(String.format("'%s'", packageName)); } } StringBuilder sb = new StringBuilder(); for (String arg : args) { sb.append(arg); sb.append('\n'); } IO.store(sb, javadocOptions); Command command = new Command(); command.add(getProperty("javadoc", "javadoc")); command.add("@" + fileName(javadocOptions)); StringBuilder out = new StringBuilder(); StringBuilder err = new StringBuilder(); int result = command.execute(out, err); if (result != 0) { warning("Error during execution of javadoc command: %s\n******************\n%s", out, err); } return new Jar(javadoc); } private String fileName(File f) { String result = f.getAbsolutePath(); if (File.separatorChar != '/') { result = result.replace(File.separatorChar, '/'); } return result; } private String escape(String input) { return input.replace("\\", "\\\\").replace(System.getProperty("line.separator"), "\\" + System.getProperty("line.separator")); } void printOverview(String name, String version, String bundleDescription) throws FileNotFoundException { Tag body = new Tag("body"); new Tag(body, "h1", name); new Tag(body, "p", "Version " + version); new Tag(body, "p", bundleDescription); Tag table = new Tag(body, "table"); for (String key : manifest) { if (key.equalsIgnoreCase(Constants.BUNDLE_DESCRIPTION) || key.equalsIgnoreCase(Constants.BUNDLE_VERSION)) continue; Tag tr = new Tag(table, "tr"); new Tag(tr, "td", key); new Tag(tr, "td", manifest.get(key)); } File overview = new File(sources, "overview.html"); try (PrintWriter pw = new PrintWriter(overview)) { body.print(2, pw); } } private void set(Properties pp, String key, String value) { if (value == null) return; if (pp.containsKey(key)) return; pp.put(key, value); } public Jar doSource() throws IOException { if (!hasSources()) return new Jar("sources"); return new Jar(sources); } public void close() throws IOException { try { super.close(); } finally { IO.delete(tmp); } } }