All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.bnd.maven.MavenCommand Maven / Gradle / Ivy

package aQute.bnd.maven;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.*;
import java.util.jar.*;
import java.util.regex.*;

import aQute.bnd.header.*;
import aQute.bnd.maven.support.*;
import aQute.bnd.maven.support.Pom.Scope;
import aQute.bnd.osgi.*;
import aQute.bnd.osgi.Descriptors.PackageRef;
import aQute.lib.collections.*;
import aQute.lib.io.*;
import aQute.lib.settings.*;
import aQute.lib.utf8properties.*;
import aQute.libg.command.*;

public class MavenCommand extends Processor {
	final Settings	settings	= new Settings();
	File			temp;

	public MavenCommand() {}

	public MavenCommand(Processor p) {
		super(p);
	}

	/**
	 * maven deploy [-url repo] [-passphrase passphrase] [-homedir homedir]
	 * [-keyname keyname] bundle ...
	 * 
	 * @param args
	 * @param i
	 * @throws Exception
	 */
	public void run(String args[], int i) throws Exception {
		temp = new File("maven-bundle");

		if (i >= args.length) {
			help();
			return;
		}

		while (i < args.length && args[i].startsWith("-")) {
			String option = args[i];
			trace("option " + option);
			if (option.equals("-temp"))
				temp = getFile(args[++i]);
			else {
				help();
				error("Invalid option " + option);
			}
			i++;
		}

		String cmd = args[i++];

		trace("temp dir " + temp);
		IO.delete(temp);
		if (!temp.exists() && !temp.mkdirs()) {
			throw new IOException("Could not create directory " + temp);
		}
		if (!temp.isDirectory())
			throw new IOException("Cannot create temp directory");

		if (cmd.equals("settings"))
			settings();
		else if (cmd.equals("help"))
			help();
		else if (cmd.equals("bundle"))
			bundle(args, i);
		else if (cmd.equals("view"))
			view(args, i);
		else
			error("No such command %s, type help", cmd);
	}

	private void help() {
		System.err.printf("Usage:%n");
		System.err
				.printf("  maven %n" //
						+ "  [-temp ]            use as temp directory%n" //
						+ "  settings                 show maven settings%n" //
						+ "  bundle                   turn a bundle into a maven bundle%n" //
						+ "    [-properties ]   provide properties, properties starting with javadoc are options for javadoc, like javadoc-tag=...%n"
						+ "    [-javadoc ]  where to find the javadoc (zip/dir), otherwise generated%n" //
						+ "    [-source ]   where to find the source (zip/dir), otherwise from OSGI-OPT/src%n" //
						+ "    [-scm ]           required scm in pom, otherwise from Bundle-SCM%n" //
						+ "    [-url ]           required project url in pom%n" //
						+ "    [-bsn bsn]             overrides bsn%n" //
						+ "    [-version ]   overrides version%n" //
						+ "    [-developer ]   developer email%n" //
						+ "    [-nodelete]            do not delete temp files%n" //
						+ "    [-passphrase ] signer password%n"//
						+ "        %n");
	}

	/**
	 * Show the maven settings
	 * 
	 * @throws FileNotFoundException
	 * @throws Exception
	 */
	private void settings() throws FileNotFoundException, Exception {
		File userHome = new File(System.getProperty("user.home"));
		File m2 = new File(userHome, ".m2");
		if (!m2.isDirectory()) {
			error("There is no m2 directory at %s", userHome);
			return;
		}
		File settings = new File(m2, "settings.xml");
		if (!settings.isFile()) {
			error("There is no settings file at '%s'", settings.getAbsolutePath());
			return;
		}
		LineCollection lc = new LineCollection(IO.reader(settings));
		try {
			while (lc.hasNext()) {
				System.err.println(lc.next());
			}
		}
		finally {
			lc.close();
		}
	}

	/**
	 * Create a maven bundle.
	 * 
	 * @param args
	 * @param i
	 * @throws Exception
	 */
	private void bundle(String args[], int i) throws Exception {
		List developers = new ArrayList();
		Properties properties = new UTF8Properties();

		String scm = null;
		String passphrase = null;
		String javadoc = null;
		String source = null;
		String output = "bundle.jar";
		String url = null;
		String artifact = null;
		String group = null;
		String version = null;
		boolean nodelete = false;

		while (i < args.length && args[i].startsWith("-")) {
			String option = args[i++];
			trace("bundle option %s", option);
			if (option.equals("-scm"))
				scm = args[i++];
			else if (option.equals("-group"))
				group = args[i++];
			else if (option.equals("-artifact"))
				artifact = args[i++];
			else if (option.equals("-version"))
				version = args[i++];
			else if (option.equals("-developer"))
				developers.add(args[i++]);
			else if (option.equals("-passphrase")) {
				passphrase = args[i++];
			} else if (option.equals("-url")) {
				url = args[i++];
			} else if (option.equals("-javadoc"))
				javadoc = args[i++];
			else if (option.equals("-source"))
				source = args[i++];
			else if (option.equals("-output"))
				output = args[i++];
			else if (option.equals("-nodelete"))
				nodelete = true;
			else if (option.startsWith("-properties")) {
				InputStream in = null;
				try {
					in = new FileInputStream(args[i++]);
					properties.load(in);
				}
				catch (Exception e) {}
				finally {
					if (in != null) {
						in.close();
					}
				}
			}
		}

		if (developers.isEmpty()) {
			String email = settings.remove("email");
			if (email == null)
				error("No developer email set, you can set global default email with: bnd global email [email protected]");
			else
				developers.add(email);
		}

		if (i == args.length) {
			error("too few arguments, no bundle specified");
			return;
		}

		if (i != args.length - 1) {
			error("too many arguments, only one bundle allowed");
			return;
		}

		String input = args[i++];

		Jar binaryJar = getJarFromFileOrURL(input);
		trace("got %s", binaryJar);
		if (binaryJar == null) {
			error("JAR does not exist: %s", input);
			return;
		}

		File original = getFile(temp, "original");
		if (!original.exists() && !original.mkdirs()) {
			throw new IOException("Could not create directory " + original);
		}
		binaryJar.expand(original);
		binaryJar.calcChecksums(null);

		Manifest manifest = binaryJar.getManifest();
		trace("got manifest");

		PomFromManifest pom = new PomFromManifest(manifest);

		if (scm != null)
			pom.setSCM(scm);
		if (url != null)
			pom.setURL(url);
		if (artifact != null)
			pom.setArtifact(artifact);
		if (artifact != null)
			pom.setGroup(group);
		if (version != null)
			pom.setVersion(version);
		trace(url);
		for (String d : developers)
			pom.addDeveloper(d);

		Set exports = OSGiHeader.parseHeader(manifest.getMainAttributes().getValue(Constants.EXPORT_PACKAGE))
				.keySet();

		Jar sourceJar;
		if (source == null) {
			trace("Splitting source code");
			sourceJar = new Jar("source");
			for (Map.Entry entry : binaryJar.getResources().entrySet()) {
				if (entry.getKey().startsWith("OSGI-OPT/src")) {
					sourceJar.putResource(entry.getKey().substring("OSGI-OPT/src/".length()), entry.getValue());
				}
			}
			copyInfo(binaryJar, sourceJar, "source");
		} else {
			sourceJar = getJarFromFileOrURL(source);
		}
		sourceJar.calcChecksums(null);

		Jar javadocJar;
		if (javadoc == null) {
			trace("creating javadoc because -javadoc not used");
			javadocJar = javadoc(getFile(original, "OSGI-OPT/src"), exports, manifest, properties);
			if (javadocJar == null) {
				error("Cannot find source code in OSGI-OPT/src to generate Javadoc");
				return;
			}
			copyInfo(binaryJar, javadocJar, "javadoc");
		} else {
			trace("Loading javadoc externally %s", javadoc);
			javadocJar = getJarFromFileOrURL(javadoc);
		}
		javadocJar.calcChecksums(null);

		addClose(binaryJar);
		addClose(sourceJar);
		addClose(javadocJar);

		trace("creating bundle dir");
		File bundle = new File(temp, "bundle");
		if (!bundle.exists() && !bundle.mkdirs()) {
			throw new IOException("Could not create directory " + bundle);
		}

		String prefix = pom.getArtifactId() + "-" + pom.getVersion();
		File binaryFile = new File(bundle, prefix + ".jar");
		File sourceFile = new File(bundle, prefix + "-sources.jar");
		File javadocFile = new File(bundle, prefix + "-javadoc.jar");
		File pomFile = new File(bundle, "pom.xml").getAbsoluteFile();
		trace("creating output files %s, %s,%s, and %s", binaryFile, sourceFile, javadocFile, pomFile);

		IO.copy(pom.openInputStream(), pomFile);
		trace("copied pom");

		trace("writing binary %s", binaryFile);
		binaryJar.write(binaryFile);

		trace("writing source %s", sourceFile);
		sourceJar.write(sourceFile);

		trace("writing javadoc %s", javadocFile);
		javadocJar.write(javadocFile);

		sign(binaryFile, passphrase);
		sign(sourceFile, passphrase);
		sign(javadocFile, passphrase);
		sign(pomFile, passphrase);

		trace("create bundle");
		Jar bundleJar = new Jar(bundle);
		addClose(bundleJar);
		File outputFile = getFile(output);
		bundleJar.write(outputFile);
		trace("created bundle %s", outputFile);

		binaryJar.close();
		sourceJar.close();
		javadocJar.close();
		bundleJar.close();
		if (!nodelete)
			IO.delete(temp);
	}

	private void copyInfo(Jar source, Jar dest, String type) throws Exception {
		source.ensureManifest();
		dest.ensureManifest();
		copyInfoResource(source, dest, "LICENSE");
		copyInfoResource(source, dest, "LICENSE.html");
		copyInfoResource(source, dest, "about.html");

		Manifest sm = source.getManifest();
		Manifest dm = dest.getManifest();
		copyInfoHeader(sm, dm, Constants.BUNDLE_DESCRIPTION, "");
		copyInfoHeader(sm, dm, Constants.BUNDLE_VENDOR, "");
		copyInfoHeader(sm, dm, Constants.BUNDLE_COPYRIGHT, "");
		copyInfoHeader(sm, dm, Constants.BUNDLE_DOCURL, "");
		copyInfoHeader(sm, dm, Constants.BUNDLE_LICENSE, "");
		copyInfoHeader(sm, dm, Constants.BUNDLE_NAME, " " + type);
		copyInfoHeader(sm, dm, Constants.BUNDLE_SYMBOLICNAME, "." + type);
		copyInfoHeader(sm, dm, Constants.BUNDLE_VERSION, "");
	}

	private void copyInfoHeader(Manifest sm, Manifest dm, String key, String value) {
		String v = sm.getMainAttributes().getValue(key);
		if (v == null) {
			trace("no source for " + key);
			return;
		}

		if (dm.getMainAttributes().getValue(key) != null) {
			trace("already have " + key);
			return;
		}

		dm.getMainAttributes().putValue(key, v + value);
	}

	private void copyInfoResource(Jar source, Jar dest, String type) {
		if (source.getResources().containsKey(type) && !dest.getResources().containsKey(type))
			dest.putResource(type, source.getResource(type));
	}

	/**
	 * @return
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	protected Jar getJarFromFileOrURL(String spec) throws IOException, MalformedURLException {
		Jar jar;
		File jarFile = getFile(spec);
		if (jarFile.exists()) {
			jar = new Jar(jarFile);
		} else {
			URL url = new URL(spec);
			InputStream in = url.openStream();
			try {
				jar = new Jar(url.getFile(), in);
			}
			finally {
				in.close();
			}
		}
		addClose(jar);
		return jar;
	}

	private void sign(File file, String passphrase) throws Exception {
		trace("signing %s", file);
		File asc = new File(file.getParentFile(), file.getName() + ".asc");
		asc.delete();

		Command command = new Command();
		command.setTrace();

		command.add(getProperty("gpg", "gpg"));
		if (passphrase != null)
			command.add("--passphrase", passphrase);
		command.add("-ab", "--sign"); // not the -b!!
		command.add(file.getAbsolutePath());
		System.err.println(command);
		StringBuilder stdout = new StringBuilder();
		StringBuilder stderr = new StringBuilder();
		int result = command.execute(stdout, stderr);
		if (result != 0) {
			error("gpg signing %s failed because %s", file, "" + stdout + stderr);
		}
	}

	private Jar javadoc(File source, Set exports, Manifest m, Properties p) throws Exception {
		File tmp = new File(temp, "javadoc");
		if (!tmp.exists() && !tmp.mkdirs()) {
			throw new IOException("Could not create directory " + tmp);
		}

		Command command = new Command();
		command.add(getProperty("javadoc", "javadoc"));
		command.add("-quiet");
		command.add("-protected");
		// command.add("-classpath");
		// command.add(binary.getAbsolutePath());
		command.add("-d");
		command.add(tmp.getAbsolutePath());
		command.add("-charset");
		command.add("UTF-8");
		command.add("-sourcepath");
		command.add(source.getAbsolutePath());

		Attributes attr = m.getMainAttributes();
		Properties pp = new UTF8Properties(p);
		set(pp, "-doctitle", description(attr));
		set(pp, "-header", description(attr));
		set(pp, "-windowtitle", name(attr));
		set(pp, "-bottom", copyright(attr));
		set(pp, "-footer", license(attr));

		command.add("-tag");
		command.add("Immutable:t:Immutable");
		command.add("-tag");
		command.add("ThreadSafe:t:ThreadSafe");
		command.add("-tag");
		command.add("NotThreadSafe:t:NotThreadSafe");
		command.add("-tag");
		command.add("GuardedBy:mf:Guarded By:");
		command.add("-tag");
		command.add("security:m:Required Permissions");
		command.add("-tag");
		command.add("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("javadoc")) {
				key = key.substring("javadoc".length());
				removeDuplicateMarker(key);
				command.add(key);
				command.add(value);
			}
		}
		for (String packageName : exports) {
			command.add(packageName);
		}

		StringBuilder out = new StringBuilder();
		StringBuilder err = new StringBuilder();

		System.err.println(command);

		int result = command.execute(out, err);
		if (result != 0) {
			warning("Error during execution of javadoc command: %s\n******************\n%s", out, err);
		}
		Jar jar = new Jar(tmp);
		addClose(jar);
		return jar;
	}

	/**
	 * Generate a license string
	 * 
	 * @param attr
	 * @return
	 */
	private String license(Attributes attr) {
		Parameters map = Processor.parseHeader(attr.getValue(Constants.BUNDLE_LICENSE), null);
		if (map.isEmpty())
			return null;

		StringBuilder sb = new StringBuilder();
		String sep = "Licensed under ";
		for (Entry entry : map.entrySet()) {
			sb.append(sep);
			String key = entry.getKey();
			String link = entry.getValue().get("link");
			String description = entry.getValue().get("description");

			if (description == null)
				description = key;

			if (link != null) {
				sb.append("");
			}
			sb.append(description);
			if (link != null) {
				sb.append("");
			}
			sep = ",
"; } return sb.toString(); } /** * Generate the copyright statement. * * @param attr * @return */ private String copyright(Attributes attr) { return attr.getValue(Constants.BUNDLE_COPYRIGHT); } private String name(Attributes attr) { String name = attr.getValue(Constants.BUNDLE_NAME); if (name == null) name = attr.getValue(Constants.BUNDLE_SYMBOLICNAME); return name; } private String description(Attributes attr) { String descr = attr.getValue(Constants.BUNDLE_DESCRIPTION); if (descr == null) descr = attr.getValue(Constants.BUNDLE_NAME); if (descr == null) descr = attr.getValue(Constants.BUNDLE_SYMBOLICNAME); return descr; } private void set(Properties pp, String option, String defaultValue) { String key = "javadoc" + option; String existingValue = pp.getProperty(key); if (existingValue != null) return; pp.setProperty(key, defaultValue); } /** * View - Show the dependency details of an artifact */ static Executor executor = Executors.newCachedThreadPool(); static Pattern GROUP_ARTIFACT_VERSION = Pattern.compile("([^+]+)\\+([^+]+)\\+([^+]+)"); void view(String args[], int i) throws Exception { Maven maven = new Maven(executor); OutputStream out = System.err; List urls = new ArrayList(); while (i < args.length && args[i].startsWith("-")) { if ("-r".equals(args[i])) { URI uri = new URI(args[++i]); urls.add(uri); System.err.println("URI for repo " + uri); } else if ("-o".equals(args[i])) { out = new FileOutputStream(args[++i]); } else throw new IllegalArgumentException("Unknown option: " + args[i]); i++; } URI[] urls2 = urls.toArray(new URI[urls.size()]); PrintWriter pw = IO.writer(out); while (i < args.length) { String ref = args[i++]; pw.println("Ref " + ref); Matcher matcher = GROUP_ARTIFACT_VERSION.matcher(ref); if (matcher.matches()) { String group = matcher.group(1); String artifact = matcher.group(2); String version = matcher.group(3); CachedPom pom = maven.getPom(group, artifact, version, urls2); Builder a = new Builder(); a.setProperty(Constants.PRIVATEPACKAGE, "*"); Set dependencies = pom.getDependencies(Scope.compile, urls2); for (Pom dep : dependencies) { System.err.printf("%20s %-20s %10s%n", dep.getGroupId(), dep.getArtifactId(), dep.getVersion()); a.addClasspath(dep.getArtifact()); } pw.println(a.getClasspath()); a.build(); TreeSet sorted = new TreeSet(a.getImports().keySet()); for (PackageRef p : sorted) { pw.printf("%-40s\n", p); } // for ( Map.Entry> entry : // a.getUses().entrySet()) { // String from = entry.getKey(); // for ( String uses : entry.getValue()) { // System.err.printf("%40s %s\n", from, uses); // from = ""; // } // } a.close(); } else System.err.println("Wrong, must look like group+artifact+version, is " + ref); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy