package org.moxie.ant; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.tools.ant.taskdefs.Jar; import org.apache.tools.ant.taskdefs.Manifest; import org.apache.tools.ant.taskdefs.Manifest.Attribute; import org.apache.tools.ant.taskdefs.ManifestException; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.ZipFileSet; import org.moxie.Build; import org.moxie.MoxieException; import org.moxie.Scope; import org.moxie.Toolkit; import org.moxie.Toolkit.Key; import org.moxie.console.Console; import org.moxie.onejar.OneJarTask; import org.moxie.utils.StringUtils; public class MxOneJar extends OneJarTask { private Console console; private List<ZipDependencies> dependencies = new ArrayList<ZipDependencies>(); private ClassSpec mainclass = null; boolean includeResources = true; boolean packageSources; String includes; String excludes; String tag; String classifier; Boolean showtitle; public boolean getIncludesresources() { return includeResources; } public void setIncluderesources(boolean copy) { this.includeResources = copy; } public String getIncludes() { return includes; } @Override public void setIncludes(String includes) { this.includes = includes; } public String getExcludes() { return excludes; } @Override public void setExcludes(String excludes) { this.excludes = excludes; } public String getTag() { return tag; } public void setTag(String tag) { this.tag = tag; } public String getClassifier() { return classifier; } public void setClassifier(String classifier) { this.classifier = classifier; } public boolean getPackagesources() { return packageSources; } public void setPackagesources(boolean sources) { this.packageSources = sources; } public void setShowtitle(boolean value) { this.showtitle = value; } public boolean isShowTitle() { return showtitle == null || showtitle; } public ZipDependencies createDependencies() { ZipDependencies deps = new ZipDependencies(); dependencies.add(deps); return deps; } /** * Builds a <mainclass> element. * * @return A <mainclass> element. */ public ClassSpec createMainclass() { if (mainclass == null) { ClassSpec cs = new ClassSpec(getProject()); mainclass = cs; return cs; } throw new MoxieException("Can only specify one main class"); } @Override public void execute() { Build build = (Build) getProject().getReference(Key.build.referenceId()); console = build.getConsole(); if (main == null && mainJars == null) { manifestSet = true; Main main = new Main(); main.setProject(getProject()); if (excludes == null) { excludes = Toolkit.DEFAULT_CODE_EXCLUDES; } // compiled output of this project File outputFolder = build.getConfig().getOutputDirectory(Scope.compile); ZipFileSet outputSet = new ZipFileSet(); outputSet.setProject(getProject()); outputSet.setDir(outputFolder); if (includes != null) { outputSet.setIncludes(includes); } outputSet.setExcludes(excludes); main.addFileSet(outputSet); // add the output and resource folders of modules for (Build module : build.getSolver().getLinkedModules()) { ZipFileSet projectOutputSet = new ZipFileSet(); projectOutputSet.setProject(getProject()); File dir = module.getConfig().getOutputDirectory(Scope.compile); projectOutputSet.setDir(dir); if (includes != null) { projectOutputSet.setIncludes(includes); } projectOutputSet.setExcludes(excludes); main.addFileSet(projectOutputSet); if (includeResources) { // add linked module resources for (File resDir : module.getConfig().getResourceDirectories(Scope.compile)) { ZipFileSet resSet = new ZipFileSet(); resSet.setProject(getProject()); resSet.setDir(resDir); resSet.setExcludes(Toolkit.DEFAULT_RESOURCE_EXCLUDES); main.addFileSet(resSet); } } } // resource directories if (includeResources) { for (File dir : build.getConfig().getResourceDirectories(Scope.compile, tag)) { ZipFileSet set = new ZipFileSet(); set.setProject(getProject()); set.setDir(dir); set.setExcludes(Toolkit.DEFAULT_RESOURCE_EXCLUDES); main.addFileSet(set); } } createDependencies().setTag(tag); if (getDestFile() == null) { setDestFile(build.getBuildArtifact(classifier)); } File destFile = getDestFile(); if (destFile.getParentFile() != null) { destFile.getParentFile().mkdirs(); } if (mainclass == null) { String mc = build.getConfig().getProjectConfig().getMainclass(); if (!StringUtils.isEmpty(mc)) { createMainclass().setName(mc); } } addMain(main); } if (mainclass != null) { String mc = mainclass.getName().replace('/', '.'); if (mc.endsWith(".class")) { mc = mc.substring(0, mc.length() - ".class".length()); } setOneJarMainClass(mc); manifestSet = true; } for (ZipDependencies deps : dependencies) { for (File jar : build.getSolver().getClasspath(deps.getScope(), deps.getTag())) { ZipFileSet fs = new ZipFileSet(); fs.setProject(getProject()); if (!StringUtils.isEmpty(deps.getPrefix())) { throw new MoxieException("Can not specify custom dependencies prefix for mx:onejar!"); } fs.setPrefix("lib/"); fs.setDir(jar.getParentFile()); fs.setIncludes(jar.getName()); addZipfileset(fs); } } if (isShowTitle()) { console.title(getClass(), getDestFile().getName()); } long start = System.currentTimeMillis(); super.execute(); console.log(1, "{0} KB, generated in {1} ms", (getDestFile().length()/1024), System.currentTimeMillis() - start); /* * Build sources jar */ if (packageSources) { String name = getDestFile().getName(); if (!StringUtils.isEmpty(classifier)) { // replace the classifier with "sources" name = name.replace(classifier, "sources"); } else { // append -sources to the filename before the extension name = name.substring(0, name.lastIndexOf('.')) + "-sources" + name.substring(name.lastIndexOf('.')); } File sourcesFile = new File(getDestFile().getParentFile(), name); if (sourcesFile.exists()) { sourcesFile.delete(); } Jar jar = new Jar(); jar.setTaskName(getTaskName()); jar.setProject(getProject()); // set the destination file jar.setDestFile(sourcesFile); List<File> folders = build.getConfig().getSourceDirectories(Scope.compile, tag); for (File folder : folders) { FileSet srcSet = new FileSet(); srcSet.setProject(getProject()); srcSet.setDir(folder); srcSet.setIncludes("**/*.java"); jar.addFileset(srcSet); // include source folder resources FileSet resSet = new FileSet(); resSet.setProject(getProject()); resSet.setDir(folder); resSet.setExcludes(excludes); jar.addFileset(resSet); } if (includeResources) { for (File dir : build.getConfig().getResourceDirectories(Scope.compile, tag)) { FileSet set = new FileSet(); set.setDir(dir); set.setExcludes(Toolkit.DEFAULT_RESOURCE_EXCLUDES); jar.addFileset(set); } } // set the source jar manifest try { Manifest mft = new Manifest(); configureManifest(mft); jar.addConfiguredManifest(mft); } catch (ManifestException e) { console.error(e); } start = System.currentTimeMillis(); jar.execute(); console.log(1, "{0} KB, generated in {1} ms", (sourcesFile.length()/1024), System.currentTimeMillis() - start); } } @Override protected void configureManifest(Manifest manifest) { // set manifest entries from Moxie metadata Manifest mft = new Manifest(); setManifest(mft, "Manifest-Version", "1.0"); setManifest(mft, "Created-By", "Moxie v" + Toolkit.getVersion()); setManifest(mft, "Build-Jdk", System.getProperty("java.version")); setManifest(mft, "Build-Date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); setManifest(mft, "Implementation-Title", Key.name); setManifest(mft, "Implementation-Vendor", Key.organization); setManifest(mft, "Implementation-Vendor-Id", Key.groupId); setManifest(mft, "Implementation-Vendor-URL", Key.url); setManifest(mft, "Implementation-Version", Key.version); setManifest(mft, "Bundle-Name", Key.name); setManifest(mft, "Bundle-SymbolicName", Key.artifactId); setManifest(mft, "Bundle-Version", Key.version); setManifest(mft, "Bundle-Vendor", Key.organization); setManifest(mft, "Maven-Url", Key.mavenUrl); setManifest(mft, "Commit-Id", Key.commitId); if (main.getManifest() == null) { // set the manifest of the embedded main jar try { File file = File.createTempFile("moxie-", ".mft"); FileOutputStream os = new FileOutputStream(file); PrintWriter writer = new PrintWriter(os); mft.write(writer); writer.flush(); os.close(); main.setManifest(file); } catch (FileNotFoundException e) { console.error(e, "Failed to set main.jar manifest!"); } catch (IOException e) { console.error(e, "Failed to set main.jar manifest!"); } } setManifest(mft, "Premain-Class", "org.moxie.onejar.Boot"); try { manifest.merge(mft, true); } catch (ManifestException e) { console.error(e, "Failed to configure manifest!"); } } void setManifest(Manifest man, String key, Key prop) { // try project property String value = getProject().getProperty(prop.projectId()); if (value == null) { return; } if (!StringUtils.isEmpty(value)) { setManifest(man, key, value); } } void setManifest(Manifest man, String key, String value) { if (!StringUtils.isEmpty(value)) { try { man.addConfiguredAttribute(new Attribute(key, value)); } catch (ManifestException e) { console.error(e, "Failed to set manifest attribute \"{0}\"!", key); } } } }