diff options
author | Mark Donszelmann <Mark.Donszelmann@gmail.com> | 2009-10-01 14:33:24 +0200 |
---|---|---|
committer | Mark Donszelmann <Mark.Donszelmann@gmail.com> | 2009-10-01 14:33:24 +0200 |
commit | 846700d44b67b22835b57a1c04f17043db8323a3 (patch) | |
tree | a253ecd4ada6f80dbcd08177035cfa71ade9b670 /src/main/java | |
parent | 0a8746644d70eb8b1cfb615c27155c19e09f46d3 (diff) | |
download | maven-nar-plugin-846700d44b67b22835b57a1c04f17043db8323a3.tar.gz maven-nar-plugin-846700d44b67b22835b57a1c04f17043db8323a3.tar.bz2 maven-nar-plugin-846700d44b67b22835b57a1c04f17043db8323a3.tar.xz maven-nar-plugin-846700d44b67b22835b57a1c04f17043db8323a3.zip |
Moved files in from freehep-nar-plugin version 2.0-alpha-11-SNAPSHOT
Diffstat (limited to 'src/main/java')
38 files changed, 5500 insertions, 0 deletions
diff --git a/src/main/java/org/apache/maven/plugin/nar/AOL.java b/src/main/java/org/apache/maven/plugin/nar/AOL.java new file mode 100644 index 0000000..3ae10c3 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/AOL.java @@ -0,0 +1,49 @@ +// Copyright FreeHEP, 2007. +package org.freehep.maven.nar; + +public class AOL { + + private String architecture; + private String os; + private String linkerName; + + // FIXME, need more complicated parsing for numbers as part of os. + public AOL(String aol) { + String[] aolString = aol.split("-", 3); + switch (aolString.length) { + case 3: + linkerName = aolString[2]; + case 2: + os = aolString[1]; + case 1: + architecture = aolString[0]; + break; + + default: + throw new RuntimeException("AOL '"+aol+"' cannot be parsed."); + } + } + + public AOL(String architecture, String os, String linkerName) { + this.architecture = architecture; + this.os = os; + this.linkerName = linkerName; + } + + public String toString() { + return architecture + + ((os == null) ? "" : "-" + os + + ((linkerName == null) ? "" : "-" + linkerName)); + } + + // FIXME, maybe change to something like isCompatible (AOL). + public boolean hasLinker(String linker) { + return linkerName.equals(linker); + } + + public String getKey() { + return architecture + + ((os == null) ? "" : "." + os + + ((linkerName == null) ? "" : "." + linkerName)); + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/AbstractCompileMojo.java b/src/main/java/org/apache/maven/plugin/nar/AbstractCompileMojo.java new file mode 100644 index 0000000..0a38229 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/AbstractCompileMojo.java @@ -0,0 +1,208 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +import org.apache.tools.ant.Project; + +/** + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/AbstractCompileMojo.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public abstract class AbstractCompileMojo extends AbstractDependencyMojo { + + /** + * C++ Compiler + * + * @parameter expression="" + */ + private Cpp cpp; + + /** + * C Compiler + * + * @parameter expression="" + */ + private C c; + + /** + * Fortran Compiler + * + * @parameter expression="" + */ + private Fortran fortran; + + /** + * Maximum number of Cores/CPU's to use. 0 means unlimited. + * + * @parameter expression="" + */ + private int maxCores = 0; + + /** + * Name of the output + * + * @parameter expression="${project.artifactId}-${project.version}" + */ + private String output; + + /** + * Fail on compilation/linking error. + * + * @parameter expression="" default-value="true" + * @required + */ + private boolean failOnError; + + /** + * Sets the type of runtime library, possible values "dynamic", "static". + * + * @parameter expression="" default-value="dynamic" + * @required + */ + private String runtime; + + /** + * Set use of libtool. If set to true, the "libtool " will be prepended to the command line for compatible processors. + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean libtool; + + /** + * The home of the Java system. + * Defaults to a derived value from ${java.home} which is OS specific. + * + * @parameter expression="" + * @readonly + */ + private File javaHome; + + /** + * List of libraries to create + * + * @parameter expression="" + */ + private List libraries; + + /** + * List of tests to create + * + * @parameter expression="" + */ + private List tests; + + /** + * Javah info + * + * @parameter expression="" + */ + private Javah javah; + + /** + * Java info for includes and linking + * + * @parameter expression="" + */ + private Java java; + + private NarInfo narInfo; + + private List/*<String>*/ dependencyLibOrder; + + private Project antProject; + + protected Project getAntProject() { + if (antProject == null) { + // configure ant project + antProject = new Project(); + antProject.setName("NARProject"); + antProject.addBuildListener(new NarLogger(getLog())); + } + return antProject; + } + + protected C getC() { + if (c == null) c = new C(); + c.setAbstractCompileMojo(this); + return c; + } + + protected Cpp getCpp() { + if (cpp == null) cpp = new Cpp(); + cpp.setAbstractCompileMojo(this); + return cpp; + } + + protected Fortran getFortran() { + if (fortran == null) fortran = new Fortran(); + fortran.setAbstractCompileMojo(this); + return fortran; + } + + protected int getMaxCores(AOL aol) { + return getNarInfo().getProperty(aol, "maxCores", maxCores); + } + + protected boolean useLibtool(AOL aol) { + return getNarInfo().getProperty(aol, "libtool", libtool); + } + + protected boolean failOnError(AOL aol) { + return getNarInfo().getProperty(aol, "failOnError", failOnError); + } + + protected String getRuntime(AOL aol) { + return getNarInfo().getProperty(aol, "runtime", runtime); + } + + protected String getOutput(AOL aol) { + return getNarInfo().getProperty(aol, "output", output); + } + + protected File getJavaHome(AOL aol) { + // FIXME should be easier by specifying default... + return getNarInfo().getProperty(aol, "javaHome", NarUtil.getJavaHome(javaHome, getOS())); + } + + protected List getLibraries() { + if (libraries == null) libraries = Collections.EMPTY_LIST; + return libraries; + } + + protected List getTests() { + if (tests == null) tests = Collections.EMPTY_LIST; + return tests; + } + + protected Javah getJavah() { + if (javah == null) javah = new Javah(); + javah.setAbstractCompileMojo(this); + return javah; + } + + protected Java getJava() { + if (java == null) java = new Java(); + java.setAbstractCompileMojo(this); + return java; + } + + public void setDependencyLibOrder(List/*<String>*/ order) { + dependencyLibOrder = order; + } + + protected List/*<String>*/ getDependencyLibOrder() { + return dependencyLibOrder; + } + + protected NarInfo getNarInfo() { + if (narInfo == null) { + narInfo = new NarInfo(getMavenProject().getGroupId(), getMavenProject() + .getArtifactId(), getMavenProject().getVersion(), getLog()); + } + return narInfo; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/AbstractDependencyMojo.java b/src/main/java/org/apache/maven/plugin/nar/AbstractDependencyMojo.java new file mode 100644 index 0000000..784027d --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/AbstractDependencyMojo.java @@ -0,0 +1,27 @@ +// Copyright FreeHEP, 2005-2006. +package org.freehep.maven.nar; + +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.plugin.MojoFailureException; + +/** + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/AbstractDependencyMojo.java c867ab546be1 2007/07/05 21:26:30 duns $ + */ +public abstract class AbstractDependencyMojo extends AbstractNarMojo { + + /** + * @parameter expression="${localRepository}" + * @required + * @readonly + */ + private ArtifactRepository localRepository; + + protected ArtifactRepository getLocalRepository() { + return localRepository; + } + + protected NarManager getNarManager() throws MojoFailureException { + return new NarManager(getLog(), getLocalRepository(), getMavenProject(), getArchitecture(), getOS(), getLinker()); + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/AbstractNarMojo.java b/src/main/java/org/apache/maven/plugin/nar/AbstractNarMojo.java new file mode 100644 index 0000000..576f27d --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/AbstractNarMojo.java @@ -0,0 +1,129 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; + + +/** + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/AbstractNarMojo.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public abstract class AbstractNarMojo extends AbstractMojo implements NarConstants { + + /** + * Skip running of NAR plugins (any) altogether. + * + * @parameter expression="${nar.skip}" default-value="false" + */ + private boolean skip; + + /** + * The Architecture for the nar, + * Some choices are: "x86", "i386", "amd64", "ppc", "sparc", ... + * Defaults to a derived value from ${os.arch} + * + * @parameter expression="${os.arch}" + * @required + */ + private String architecture; + + /** + * The Operating System for the nar. + * Some choices are: "Windows", "Linux", "MacOSX", "SunOS", ... + * Defaults to a derived value from ${os.name} + * FIXME table missing + * + * @parameter expression="" + */ + private String os; + + /** + * Architecture-OS-Linker name. + * Defaults to: arch-os-linker. + * + * @parameter expression="" + */ + private String aol; + + /** + * Linker + * + * @parameter expression="" + */ + private Linker linker; + + /** + * @parameter expression="${project.build.directory}" + * @readonly + */ + private File outputDirectory; + + /** + * @parameter expression="${project.build.finalName}" + * @readonly + */ + private String finalName; + + /** + * Target directory for Nar file construction + * Defaults to "${project.build.directory}/nar" for "nar-compile" goal + * Defaults to "${project.build.directory}/test-nar" for "nar-testCompile" goal + * + * @parameter expression="" + */ + private File targetDirectory; + + /** + * @parameter expression="${project}" + * @readonly + * @required + */ + private MavenProject mavenProject; + + + protected boolean shouldSkip() { + return skip; + } + + protected String getArchitecture() { + architecture = NarUtil.getArchitecture(architecture); + return architecture; + } + + protected String getOS() { + os = NarUtil.getOS(os); + return os; + } + + protected AOL getAOL() throws MojoFailureException { + return NarUtil.getAOL(architecture, os, linker, aol); + } + + protected Linker getLinker() { + linker = NarUtil.getLinker(linker); + return linker; + } + + protected File getOutputDirectory() { + return outputDirectory; + } + + protected String getFinalName() { + return finalName; + } + + protected File getTargetDirectory() { + if (targetDirectory == null) { + targetDirectory = new File(mavenProject.getBuild().getDirectory(), "nar"); + } + return targetDirectory; + } + + protected MavenProject getMavenProject() { + return mavenProject; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/AttachedNarArtifact.java b/src/main/java/org/apache/maven/plugin/nar/AttachedNarArtifact.java new file mode 100644 index 0000000..cf6881d --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/AttachedNarArtifact.java @@ -0,0 +1,66 @@ +// Copyright 2005-2007, FreeHEP. +package org.freehep.maven.nar; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; + +/** + * NarArtifact with its own type, classifier and artifactHandler. + * + * @author Mark Donszelmann + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/AttachedNarArtifact.java 54f05023f537 2007/07/24 05:44:30 duns $ + */ +public class AttachedNarArtifact extends DefaultArtifact { + + public AttachedNarArtifact(String groupId, String artifactId, String version, String scope, + String type, String classifier, boolean optional) throws InvalidVersionSpecificationException { + super(groupId, artifactId, VersionRange.createFromVersionSpec(version), scope, + type, classifier, null, optional); + setArtifactHandler(new Handler(classifier)); + } + + public AttachedNarArtifact(Artifact parent, String type, String classifier) { + super(parent.getGroupId(), parent.getArtifactId(), parent.getVersionRange(), parent.getScope(), + type, classifier, null, parent.isOptional()); + setArtifactHandler(new Handler(classifier)); + } + + private class Handler implements ArtifactHandler { + private String classifier; + + Handler(String classifier) { + this.classifier = classifier; + } + + public String getExtension() { + return "nar"; + } + + public String getDirectory() { + return "nars"; + } + + public String getClassifier() { + return classifier; + } + + public String getPackaging() { + return "nar"; + } + + public boolean isIncludesDependencies() { + return false; + } + + public String getLanguage() { + return "native"; + } + + public boolean isAddedToClasspath() { + return false; + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/C.java b/src/main/java/org/apache/maven/plugin/nar/C.java new file mode 100644 index 0000000..7826874 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/C.java @@ -0,0 +1,18 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +/** + * C compiler tag + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/C.java 631dc18040bb 2007/07/17 14:21:11 duns $ + */ +public class C extends Compiler { + + public C() { + } + + public String getName() { + return "c"; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Compiler.java b/src/main/java/org/apache/maven/plugin/nar/Compiler.java new file mode 100644 index 0000000..6f5a44a --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Compiler.java @@ -0,0 +1,496 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.CompilerDef; +import net.sf.antcontrib.cpptasks.CompilerEnum; +import net.sf.antcontrib.cpptasks.OptimizationEnum; +import net.sf.antcontrib.cpptasks.types.CompilerArgument; +import net.sf.antcontrib.cpptasks.types.ConditionalFileSet; +import net.sf.antcontrib.cpptasks.types.DefineArgument; +import net.sf.antcontrib.cpptasks.types.DefineSet; + +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.StringUtils; + +/** + * Abstract Compiler class + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Compiler.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public abstract class Compiler { + + /** + * The name of the compiler Some choices are: "msvc", "g++", "gcc", "CC", + * "cc", "icc", "icpc", ... Default is Architecture-OS-Linker specific: + * FIXME: table missing + * + * @parameter expression="" + */ + private String name; + + /** + * Source directory for native files + * + * @parameter expression="${basedir}/src/main" + * @required + */ + private File sourceDirectory; + + /** + * Include patterns for sources + * + * @parameter expression="" + * @required + */ + private Set includes = new HashSet(); + + /** + * Exclude patterns for sources + * + * @parameter expression="" + * @required + */ + private Set excludes = new HashSet(); + + /** + * Compile with debug information. + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean debug = false; + + /** + * Enables generation of exception handling code. + * + * @parameter expression="" default-value="true" + * @required + */ + private boolean exceptions = true; + + /** + * Enables run-time type information. + * + * @parameter expression="" default-value="true" + * @required + */ + private boolean rtti = true; + + /** + * Sets optimization. Possible choices are: "none", "size", "minimal", + * "speed", "full", "aggressive", "extreme", "unsafe". + * + * @parameter expression="" default-value="none" + * @required + */ + private String optimize = "none"; + + /** + * Enables or disables generation of multi-threaded code. Default value: + * false, except on Windows. + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean multiThreaded = false; + + /** + * Defines + * + * @parameter expression="" + */ + private List defines; + + /** + * Defines for the compiler as a comma separated list of name[=value] pairs, where the value is optional. + * Will work in combination with <defines>. + * + * @parameter expression="" + */ + private String defineSet; + + /** + * Clears default defines + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean clearDefaultDefines; + + /** + * Undefines + * + * @parameter expression="" + */ + private List undefines; + + /** + * Undefines for the compiler as a comma separated list of name[=value] pairs where the value is optional. + * Will work in combination with <undefines>. + * + * @parameter expression="" + */ + private String undefineSet; + + /** + * Clears default undefines + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean clearDefaultUndefines; + + /** + * Include Paths. Defaults to "${sourceDirectory}/include" + * + * @parameter expression="" + */ + private List includePaths; + + /** + * System Include Paths, which are added at the end of all include paths + * + * @parameter expression="" + */ + private List systemIncludePaths; + + /** + * Additional options for the C++ compiler Defaults to + * Architecture-OS-Linker specific values. FIXME table missing + * + * @parameter expression="" + */ + private List options; + + /** + * Options for the compiler as a whitespace separated list. + * Will work in combination with <options>. + * + * @parameter expression="" + */ + private String optionSet; + + /** + * Clears default options + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean clearDefaultOptions; + + private AbstractCompileMojo mojo; + + protected Compiler() { + } + + public void setAbstractCompileMojo(AbstractCompileMojo mojo) { + this.mojo = mojo; + } + + public File getSourceDirectory() { + return getSourceDirectory("dummy"); + } + + protected File getSourceDirectory(String type) { + if (sourceDirectory == null) { + sourceDirectory = new File(mojo.getMavenProject().getBasedir(), + "src/" + (type.equals("test") ? "test" : "main")); + } + return sourceDirectory; + } + + protected List/* <String> */getIncludePaths(String type) { + if (includePaths == null || (includePaths.size() == 0)) { + includePaths = new ArrayList(); + includePaths.add(new File(getSourceDirectory(type), "include") + .getPath()); + } + return includePaths; + } + + public Set getIncludes() throws MojoFailureException { + return getIncludes("main"); + } + + protected Set getIncludes(String type) throws MojoFailureException { + Set result = new HashSet(); + if (!type.equals("test") && !includes.isEmpty()) { + result.addAll(includes); + } else { + String defaultIncludes = NarUtil.getDefaults().getProperty( + getPrefix() + "includes"); + if (defaultIncludes == null) { + throw new MojoFailureException( + "NAR: Please specify <Includes> as part of <Cpp>, <C> or <Fortran> for " + + getPrefix()); + } + + String[] include = defaultIncludes.split(" "); + for (int i = 0; i < include.length; i++) { + result.add(include[i].trim()); + } + } + return result; + } + + protected Set getExcludes() throws MojoFailureException { + Set result = new HashSet(); + + // add all excludes + if (excludes.isEmpty()) { + String defaultExcludes = NarUtil.getDefaults().getProperty( + getPrefix() + "excludes"); + if (defaultExcludes != null) { + String[] exclude = defaultExcludes.split(" "); + for (int i = 0; i < exclude.length; i++) { + result.add(exclude[i].trim()); + } + } + } else { + result.addAll(excludes); + } + + return result; + } + + protected String getPrefix() throws MojoFailureException { + return mojo.getAOL().getKey() + "." + getName() + "."; + } + + public CompilerDef getCompiler(String type, String output) + throws MojoFailureException { + + // adjust default values + if (name == null) + name = NarUtil.getDefaults().getProperty(getPrefix() + "compiler"); + if (name == null) { + throw new MojoFailureException( + "NAR: Please specify <Name> as part of <Cpp>, <C> or <Fortran> for " + + getPrefix()); + } + + CompilerDef compiler = new CompilerDef(); + compiler.setProject(mojo.getAntProject()); + CompilerEnum compilerName = new CompilerEnum(); + compilerName.setValue(name); + compiler.setName(compilerName); + + // debug, exceptions, rtti, multiThreaded + compiler.setDebug(debug); + compiler.setExceptions(exceptions); + compiler.setRtti(rtti); + compiler.setMultithreaded(mojo.getOS().equals("Windows") ? true + : multiThreaded); + + // optimize + OptimizationEnum optimization = new OptimizationEnum(); + optimization.setValue(optimize); + compiler.setOptimize(optimization); + + // add options + if (options != null) { + for (Iterator i = options.iterator(); i.hasNext();) { + CompilerArgument arg = new CompilerArgument(); + arg.setValue((String) i.next()); + compiler.addConfiguredCompilerArg(arg); + } + } + + if (optionSet != null) { + + String[] opts = optionSet.split("\\s"); + + for (int i = 0; i < opts.length; i++) { + + CompilerArgument arg = new CompilerArgument(); + + arg.setValue(opts[i]); + compiler.addConfiguredCompilerArg(arg); + } + } + + if (!clearDefaultOptions) { + String optionsProperty = NarUtil.getDefaults().getProperty( + getPrefix() + "options"); + if (optionsProperty != null) { + String[] option = optionsProperty.split(" "); + for (int i = 0; i < option.length; i++) { + CompilerArgument arg = new CompilerArgument(); + arg.setValue(option[i]); + compiler.addConfiguredCompilerArg(arg); + } + } + } + + // add defines + if (defines != null) { + DefineSet defineSet = new DefineSet(); + for (Iterator i = defines.iterator(); i.hasNext();) { + DefineArgument define = new DefineArgument(); + String[] pair = ((String) i.next()).split("=", 2); + define.setName(pair[0]); + define.setValue(pair.length > 1 ? pair[1] : null); + defineSet.addDefine(define); + } + compiler.addConfiguredDefineset(defineSet); + } + + if (defineSet != null) { + + String[] defList = defineSet.split(","); + DefineSet defSet = new DefineSet(); + + for (int i = 0; i < defList.length; i++) { + + String[] pair = defList[i].trim().split("=", 2); + DefineArgument def = new DefineArgument(); + + def.setName(pair[0]); + def.setValue(pair.length > 1 ? pair[1] : null); + + defSet.addDefine(def); + } + + compiler.addConfiguredDefineset(defSet); + } + + if (!clearDefaultDefines) { + DefineSet defineSet = new DefineSet(); + String defaultDefines = NarUtil.getDefaults().getProperty( + getPrefix() + "defines"); + if (defaultDefines != null) { + defineSet + .setDefine(new CUtil.StringArrayBuilder(defaultDefines)); + } + compiler.addConfiguredDefineset(defineSet); + } + + // add undefines + if (undefines != null) { + DefineSet undefineSet = new DefineSet(); + for (Iterator i = undefines.iterator(); i.hasNext();) { + DefineArgument undefine = new DefineArgument(); + String[] pair = ((String) i.next()).split("=", 2); + undefine.setName(pair[0]); + undefine.setValue(pair.length > 1 ? pair[1] : null); + undefineSet.addUndefine(undefine); + } + compiler.addConfiguredDefineset(undefineSet); + } + + if (undefineSet != null) { + + String[] undefList = undefineSet.split(","); + DefineSet undefSet = new DefineSet(); + + for (int i = 0; i < undefList.length; i++) { + + String[] pair = undefList[i].trim().split("=", 2); + DefineArgument undef = new DefineArgument(); + + undef.setName(pair[0]); + undef.setValue(pair.length > 1 ? pair[1] : null); + + undefSet.addUndefine(undef); + } + + compiler.addConfiguredDefineset(undefSet); + } + + if (!clearDefaultUndefines) { + DefineSet undefineSet = new DefineSet(); + String defaultUndefines = NarUtil.getDefaults().getProperty( + getPrefix() + "undefines"); + if (defaultUndefines != null) { + undefineSet.setUndefine(new CUtil.StringArrayBuilder( + defaultUndefines)); + } + compiler.addConfiguredDefineset(undefineSet); + } + + // add include path + for (Iterator i = getIncludePaths(type).iterator(); i.hasNext();) { + String path = (String) i.next(); + compiler.createIncludePath().setPath(path); + } + + // add system include path (at the end) + if (systemIncludePaths != null) { + for (Iterator i = systemIncludePaths.iterator(); i.hasNext();) { + String path = (String) i.next(); + compiler.createSysIncludePath().setPath(path); + } + } + + // Add default fileset (if exists) + File srcDir = getSourceDirectory(type); + Set includes = getIncludes(); + Set excludes = getExcludes(); + + // now add all but the current test to the excludes + for (Iterator i = mojo.getTests().iterator(); i.hasNext();) { + Test test = (Test) i.next(); + if (!test.getName().equals(output)) { + excludes.add("**/" + test.getName() + ".*"); + } + } + + mojo.getLog().debug( + "Checking for existence of " + getName() + " sourceDirectory: " + + srcDir); + if (srcDir.exists()) { + ConditionalFileSet fileSet = new ConditionalFileSet(); + fileSet.setProject(mojo.getAntProject()); + fileSet.setIncludes(StringUtils.join(includes.iterator(), ",")); + fileSet.setExcludes(StringUtils.join(excludes.iterator(), ",")); + fileSet.setDir(srcDir); + compiler.addFileset(fileSet); + } + + // add other sources + if (!type.equals("test")) { + for (Iterator i = mojo.getMavenProject().getCompileSourceRoots() + .iterator(); i.hasNext();) { + File dir = new File((String) i.next()); + mojo.getLog().debug( + "Checking for existence of " + getName() + + " sourceCompileRoot: " + dir); + if (dir.exists()) { + ConditionalFileSet otherFileSet = new ConditionalFileSet(); + otherFileSet.setProject(mojo.getAntProject()); + otherFileSet.setIncludes(StringUtils.join(includes + .iterator(), ",")); + otherFileSet.setExcludes(StringUtils.join(excludes + .iterator(), ",")); + otherFileSet.setDir(dir); + compiler.addFileset(otherFileSet); + } + } + } + return compiler; + } + + protected abstract String getName(); + + public void copyIncludeFiles(MavenProject mavenProject, File targetDirectory) + throws IOException { + for (Iterator i = getIncludePaths("dummy").iterator(); i.hasNext();) { + File path = new File((String) i.next()); + if (path.exists()) { + NarUtil.copyDirectoryStructure(path, targetDirectory, null, + NarUtil.DEFAULT_EXCLUDES); + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Cpp.java b/src/main/java/org/apache/maven/plugin/nar/Cpp.java new file mode 100644 index 0000000..8b13b18 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Cpp.java @@ -0,0 +1,17 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +/** + * Cpp compiler tag + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Cpp.java 631dc18040bb 2007/07/17 14:21:11 duns $ + */ +public class Cpp extends Compiler { + public Cpp() { + } + + public String getName() { + return "cpp"; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Executable.java b/src/main/java/org/apache/maven/plugin/nar/Executable.java new file mode 100644 index 0000000..0762f64 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Executable.java @@ -0,0 +1,10 @@ +package org.freehep.maven.nar; + +import java.util.List; + +public interface Executable { + + public boolean shouldRun(); + + public List/*<String>*/ getArgs(); +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Fortran.java b/src/main/java/org/apache/maven/plugin/nar/Fortran.java new file mode 100644 index 0000000..033a94f --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Fortran.java @@ -0,0 +1,18 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +/** + * Fortran compiler tag + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Fortran.java 0c1f0fc112ac 2007/09/12 18:18:23 duns $ + */ +public class Fortran extends Compiler { + + public Fortran() { + } + + public String getName() { + return "fortran"; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Java.java b/src/main/java/org/apache/maven/plugin/nar/Java.java new file mode 100644 index 0000000..ac6d4c0 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Java.java @@ -0,0 +1,126 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import net.sf.antcontrib.cpptasks.CCTask; +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.types.CommandLineArgument; +import net.sf.antcontrib.cpptasks.types.LibrarySet; +import net.sf.antcontrib.cpptasks.types.LinkerArgument; + +import org.apache.maven.plugin.MojoFailureException; + +/** + * Java specifications for NAR + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Java.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public class Java { + + /** + * Add Java includes to includepath + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean include = false; + + /** + * Java Include Paths, relative to a derived ${java.home}. + * Defaults to: "${java.home}/include" and "${java.home}/include/<i>os-specific</i>". + * + * @parameter expression="" + */ + private List includePaths; + + /** + * Add Java Runtime to linker + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean link = false; + + /** + * Relative path from derived ${java.home} to the java runtime to link with + * Defaults to Architecture-OS-Linker specific value. + * FIXME table missing + * + * @parameter expression="" + */ + private String runtimeDirectory; + + /** + * Name of the runtime + * + * @parameter expression="" default-value="jvm" + */ + private String runtime = "jvm"; + + private AbstractCompileMojo mojo; + + public Java() { + } + + public void setAbstractCompileMojo(AbstractCompileMojo mojo) { + this.mojo = mojo; + } + + public void addIncludePaths(CCTask task, String outType) throws MojoFailureException { + if (include || mojo.getJavah().getJniDirectory().exists()) { + if (includePaths != null) { + for (Iterator i=includePaths.iterator(); i.hasNext(); ) { + String path = (String)i.next(); + task.createIncludePath().setPath(new File(mojo.getJavaHome(mojo.getAOL()), path).getPath()); + } + } else { + String prefix = mojo.getAOL().getKey()+".java."; + String includes = NarUtil.getDefaults().getProperty(prefix+"include"); + if (includes != null) { + String[] path = includes.split(";"); + for (int i=0; i<path.length; i++) { + task.createIncludePath().setPath(new File(mojo.getJavaHome(mojo.getAOL()), path[i]).getPath()); + } + } + } + } + } + + public void addRuntime(CCTask task, File javaHome, String os, String prefix) throws MojoFailureException { + if (link) { + if (os.equals(OS.MACOSX)) { + CommandLineArgument.LocationEnum end = new CommandLineArgument.LocationEnum(); + end.setValue("end"); + + // add as argument rather than library to avoid argument quoting + LinkerArgument framework = new LinkerArgument(); + framework.setValue("-framework"); + framework.setLocation(end); + task.addConfiguredLinkerArg(framework); + + LinkerArgument javavm = new LinkerArgument(); + javavm.setValue("JavaVM"); + javavm.setLocation(end); + task.addConfiguredLinkerArg(javavm); + } else { + if (runtimeDirectory == null) { + runtimeDirectory = NarUtil.getDefaults().getProperty(prefix+"runtimeDirectory"); + if (runtimeDirectory == null) { + throw new MojoFailureException("NAR: Please specify a <RuntimeDirectory> as part of <Java>"); + } + } + mojo.getLog().debug("Using Java Rumtime Directory: "+runtimeDirectory); + + LibrarySet libset = new LibrarySet(); + libset.setProject(mojo.getAntProject()); + libset.setLibs(new CUtil.StringArrayBuilder(runtime)); + libset.setDir(new File(javaHome, runtimeDirectory)); + task.addLibset(libset); + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Javah.java b/src/main/java/org/apache/maven/plugin/nar/Javah.java new file mode 100644 index 0000000..7141ab4 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Javah.java @@ -0,0 +1,237 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.bcel.classfile.ClassFormatException; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.compiler.util.scan.InclusionScanException; +import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner; +import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner; +import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping; +import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.StringUtils; + +/** + * Sets up the javah configuration + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Javah.java eeac31f37379 2007/07/24 04:02:00 duns $ + */ +public class Javah { + + /** + * Javah command to run. + * + * @parameter default-value="javah" + */ + private String name = "javah"; + + /** + * Add boot class paths. By default none. + * + * @parameter + */ + private List/*<File>*/ bootClassPaths = new ArrayList(); + + /** + * Add class paths. By default the classDirectory directory is included and all dependent classes. + * + * @parameter + */ + private List/*<File>*/ classPaths = new ArrayList(); + + /** + * The target directory into which to generate the output. + * + * @parameter expression="${project.build.directory}/nar/javah-include" + * @required + */ + private File jniDirectory; + + /** + * The class directory to scan for class files with native interfaces. + * + * @parameter expression="${project.build.directory}/classes" + * @required + */ + private File classDirectory; + + /** + * The set of files/patterns to include + * Defaults to "**\/*.class" + * + * @parameter + */ + private Set includes = new HashSet(); + + /** + * A list of exclusion filters. + * + * @parameter + */ + private Set excludes = new HashSet(); + + /** + * The granularity in milliseconds of the last modification + * date for testing whether a source needs recompilation + * + * @parameter default-value="0" + * @required + */ + private int staleMillis = 0; + + /** + * The directory to store the timestampfile for the processed aid files. Defaults to jniDirectory. + * + * @parameter + */ + private File timestampDirectory; + + /** + * The timestampfile for the processed class files. Defaults to name of javah. + * + * @parameter + */ + private File timestampFile; + + private AbstractCompileMojo mojo; + + public Javah() { + } + + public void setAbstractCompileMojo(AbstractCompileMojo mojo) { + this.mojo = mojo; + } + + protected List getClassPaths() throws MojoExecutionException { + if (classPaths.isEmpty()) { + try { + classPaths.addAll(mojo.getMavenProject().getCompileClasspathElements()); + } catch (DependencyResolutionRequiredException e) { + throw new MojoExecutionException("JAVAH, cannot get classpath", e); + } + } + return classPaths; + } + + protected File getJniDirectory() { + if (jniDirectory == null) { + jniDirectory = new File(mojo.getMavenProject().getBuild().getDirectory(), "nar/javah-include"); + } + return jniDirectory; + } + + protected File getClassDirectory() { + if (classDirectory == null) { + classDirectory = new File(mojo.getMavenProject().getBuild().getDirectory(), "classes"); + } + return classDirectory; + } + + protected Set getIncludes() { + if (includes.isEmpty()) { + includes.add("**/*.class"); + } + return includes; + } + + protected File getTimestampDirectory() { + if (timestampDirectory == null) { + timestampDirectory = getJniDirectory(); + } + return timestampDirectory; + } + + protected File getTimestampFile() { + if (timestampFile == null) { + timestampFile = new File(name); + } + return timestampFile; + } + + public void execute() throws MojoExecutionException, MojoFailureException { + getClassDirectory().mkdirs(); + + try { + SourceInclusionScanner scanner = new StaleSourceScanner(staleMillis, getIncludes(), excludes); + if (getTimestampDirectory().exists()) { + scanner.addSourceMapping(new SingleTargetSourceMapping( ".class", getTimestampFile().getPath() )); + } else { + scanner.addSourceMapping(new SuffixMapping( ".class", ".dummy" )); + } + + Set classes = scanner.getIncludedSources(getClassDirectory(), getTimestampDirectory()); + + if (!classes.isEmpty()) { + Set files = new HashSet(); + for (Iterator i=classes.iterator(); i.hasNext(); ) { + String file = ((File)i.next()).getPath(); + JavaClass clazz = NarUtil.getBcelClass(file); + Method[] method = clazz.getMethods(); + for (int j=0; j<method.length; j++) { + if (method[j].isNative()) files.add(clazz.getClassName()); + } + } + + if (!files.isEmpty()) { + getJniDirectory().mkdirs(); + getTimestampDirectory().mkdirs(); + + mojo.getLog().info( "Running "+name+" compiler on "+files.size()+" classes..."); + int result = NarUtil.runCommand(name, generateArgs(files), null, mojo.getLog()); + if (result != 0) { + throw new MojoFailureException(name+" failed with exit code "+result+" 0x"+Integer.toHexString(result)); + } + FileUtils.fileWrite(getTimestampDirectory()+"/"+getTimestampFile(), ""); + } + } + } catch (InclusionScanException e) { + throw new MojoExecutionException( "JAVAH: Class scanning failed", e ); + } catch (IOException e) { + throw new MojoExecutionException( "JAVAH: IO Exception", e ); + } catch (ClassFormatException e) { + throw new MojoExecutionException( "JAVAH: Class could not be inspected", e); + } + } + + private String[] generateArgs(Set/*<String>*/ classes) throws MojoExecutionException { + + List args = new ArrayList(); + + if (!bootClassPaths.isEmpty()) { + args.add("-bootclasspath"); + args.add(StringUtils.join(bootClassPaths.iterator(), File.pathSeparator)); + } + + args.add("-classpath"); + args.add(StringUtils.join(getClassPaths().iterator(), File.pathSeparator)); + + args.add("-d"); + args.add(getJniDirectory().getPath()); + + if (mojo.getLog().isDebugEnabled()) { + args.add("-verbose"); + } + + if (classes != null) { + for (Iterator i = classes.iterator(); i.hasNext(); ) { + args.add((String)i.next()); + } + } + + return (String[])args.toArray(new String[args.size()]); + } +} + diff --git a/src/main/java/org/apache/maven/plugin/nar/Lib.java b/src/main/java/org/apache/maven/plugin/nar/Lib.java new file mode 100644 index 0000000..6f47527 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Lib.java @@ -0,0 +1,97 @@ +// Copyright FreeHEP, 2005. +package org.freehep.maven.nar; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.LinkerDef; +import net.sf.antcontrib.cpptasks.types.LibrarySet; +import net.sf.antcontrib.cpptasks.types.LibraryTypeEnum; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.tools.ant.Project; + +/** + * Keeps info on a library + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Lib.java eda4d0bbde3d 2007/07/03 16:52:10 duns $ + */ +public class Lib { + + /** + * Name of the library, or a dependency groupId:artifactId if this library contains sublibraries + * + * @parameter expression="" + * @required + */ + private String name; + + /** + * Type of linking for this library + * + * @parameter expression="" default-value="shared" + * @required + */ + private String type = Library.SHARED; + + /** + * Location for this library + * + * @parameter expression="" + * @required + */ + private File directory; + + /** + * Sub libraries for this library + * + * @parameter expression="" + */ + private List/*<Lib>*/ libs; + + public void addLibSet(AbstractDependencyMojo mojo, LinkerDef linker, Project antProject) throws MojoFailureException, MojoExecutionException { + addLibSet(mojo, linker, antProject, name, directory); + } + + private void addLibSet(AbstractDependencyMojo mojo, LinkerDef linker, Project antProject, String name, File dir) throws MojoFailureException, MojoExecutionException { + if (name == null) { + throw new MojoFailureException("NAR: Please specify <Name> as part of <Lib>"); + } + if (libs == null) { + if (!type.equals("framework") && (dir == null)) { + throw new MojoFailureException("NAR: Please specify <Directory> as part of <Lib>"); + } + LibrarySet libSet = new LibrarySet(); + libSet.setProject(antProject); + libSet.setLibs(new CUtil.StringArrayBuilder(name)); + LibraryTypeEnum libType = new LibraryTypeEnum(); + libType.setValue(type); + libSet.setType(libType); + libSet.setDir(dir); + linker.addLibset(libSet); + } else { + List dependencies = mojo.getNarManager().getNarDependencies("compile"); + for (Iterator i=libs.iterator(); i.hasNext(); ) { + Lib lib = (Lib)i.next(); + String[] ids = name.split(":",2); + if (ids.length != 2) { + throw new MojoFailureException("NAR: Please specify <Name> as part of <Lib> in format 'groupId:artifactId'"); + } + for (Iterator j=dependencies.iterator(); j.hasNext(); ) { + Artifact dependency = (Artifact)j.next(); + if (dependency.getGroupId().equals(ids[0]) && dependency.getArtifactId().equals(ids[1])) { + File narDir = new File(mojo.getNarManager().getNarFile(dependency).getParentFile(), "nar/lib/"+mojo.getAOL()+"/"+lib.type); + String narName = dependency.getArtifactId()+"-"+lib.name+"-"+dependency.getVersion(); + lib.addLibSet(mojo, linker, antProject, narName, narDir); + } + } + } + } + } +} + diff --git a/src/main/java/org/apache/maven/plugin/nar/Library.java b/src/main/java/org/apache/maven/plugin/nar/Library.java new file mode 100644 index 0000000..abda679 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Library.java @@ -0,0 +1,117 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * Sets up a library to create + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Library.java 19804ec9b6b9 2007/09/04 23:36:51 duns $ + */ +public class Library implements Executable { + + public static final String STATIC = "static"; + public static final String SHARED = "shared"; + public static final String EXECUTABLE = "executable"; + public static final String JNI = "jni"; + public static final String PLUGIN = "plugin"; + public static final String NONE = "none"; // no library produced + + /** + * Type of the library to generate. Possible choices are: "plugin", + * "shared", "static", "jni" or "executable". Defaults to "shared". + * + * @parameter expression="" + */ + protected String type = "shared"; + + /** + * Link with stdcpp if necessary Defaults to true. + * + * @parameter expression="" + */ + protected boolean linkCPP = true; + + /** + * Link with fortran runtime if necessary Defaults to false. + * + * @parameter expression="" + */ + protected boolean linkFortran = false; + + /** + * If specified will create the NarSystem class with methods + * to load a JNI library. + * + * @parameter expression="" + */ + protected String narSystemPackage = null; + + /** + * Name of the NarSystem class + * + * @parameter expression="NarSystem" + * @required + */ + protected String narSystemName = "NarSystem"; + + /** + * The target directory into which to generate the output. + * + * @parameter expression="${project.build.dir}/nar/nar-generated" + * @required + */ + protected File narSystemDirectory = new File("target/nar/nar-generated"); + + /** + * When true and if type is "executable" run this executable. + * Defaults to false; + * + * @parameter expression="" + */ + protected boolean run=false; + + /** + * Arguments to be used for running this executable. + * Defaults to empty list. This option is + * only used if run=true and type=executable. + * + * @parameter expression="" + */ + protected List/*<String>*/ args = new ArrayList(); + + public String getType() { + return type; + } + + public boolean linkCPP() { + return linkCPP; + } + + public boolean linkFortran() { + return linkFortran; + } + + public String getNarSystemPackage() { + return narSystemPackage; + } + + public boolean shouldRun() { + return run; + } + + public List/*<String>*/ getArgs() { + return args; + } + + public String getNarSystemName() { + return narSystemName; + } + + public File getNarSystemDirectory() { + return narSystemDirectory; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Linker.java b/src/main/java/org/apache/maven/plugin/nar/Linker.java new file mode 100644 index 0000000..e148b31 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Linker.java @@ -0,0 +1,348 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.LinkedList; + +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.LinkerDef; +import net.sf.antcontrib.cpptasks.LinkerEnum; +import net.sf.antcontrib.cpptasks.types.LibrarySet; +import net.sf.antcontrib.cpptasks.types.LibraryTypeEnum; +import net.sf.antcontrib.cpptasks.types.LinkerArgument; +import net.sf.antcontrib.cpptasks.types.SystemLibrarySet; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.tools.ant.Project; +import org.codehaus.plexus.util.FileUtils; + +/** + * Linker tag + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Linker.java 22df3eb318cc 2007/09/06 18:55:15 duns $ + */ +public class Linker { + + /** + * The Linker Some choices are: "msvc", "g++", "CC", "icpc", ... Default is + * Architecture-OS-Linker specific: FIXME: table missing + * + * @parameter expression="" + */ + private String name; + + /** + * Enables or disables incremental linking. + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean incremental = false; + + /** + * Enables or disables the production of a map file. + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean map = false; + + /** + * Options for the linker Defaults to Architecture-OS-Linker specific + * values. FIXME table missing + * + * @parameter expression="" + */ + private List options; + + /** + * Options for the linker as a whitespace separated list. + * Defaults to Architecture-OS-Linker specific values. + * Will work in combination with <options>. + * + * @parameter expression="" + */ + private String optionSet; + + /** + * Clears default options + * + * @parameter expression="" default-value="false" + * @required + */ + private boolean clearDefaultOptions; + + /** + * Adds libraries to the linker. + * + * @parameter expression="" + */ + private List/* <Lib> */libs; + + /** + * Adds libraries to the linker. Will work in combination with <libs>. + * The format is comma separated, colon-delimited values (name:type:dir), + * like "myLib:shared:/home/me/libs/, otherLib:static:/some/path". + * + * @parameter expression="" + */ + private String libSet; + + /** + * Adds system libraries to the linker. + * + * @parameter expression="" + */ + private List/* <SysLib> */sysLibs; + + /** + * Adds system libraries to the linker. Will work in combination with <sysLibs>. + * The format is comma separated, colon-delimited values (name:type), + * like "dl:shared, pthread:shared". + * + * @parameter expression="" + */ + private String sysLibSet; + + /** + * <p> + * Specifies the link ordering of libraries that come from nar dependencies. The format is + * a comma separated list of dependency names, given as groupId:artifactId. + * </p> + * + * <p> + * Example: <narDependencyLibOrder>someGroup:myProduct, other.group:productB<narDependencyLibOrder> + * </p> + * + * @parameter expression="" + */ + private String narDependencyLibOrder; + + + public Linker() { + // default constructor for use as TAG + } + + /** + * For use with specific named linker. + * + * @param name + */ + public Linker(String name) { + this.name = name; + } + + public String getName(Properties defaults, String prefix) + throws MojoFailureException { + if ((name == null) && (defaults != null) && (prefix != null)) { + name = defaults.getProperty(prefix + "linker"); + } + if (name == null) { + throw new MojoFailureException( + "NAR: Please specify a <Name> as part of <Linker>"); + } + return name; + } + + public LinkerDef getLinker(AbstractCompileMojo mojo, Project antProject, + String os, String prefix, String type) throws MojoFailureException, + MojoExecutionException { + if (name == null) { + throw new MojoFailureException( + "NAR: Please specify a <Name> as part of <Linker>"); + } + + LinkerDef linker = new LinkerDef(); + linker.setProject(antProject); + LinkerEnum linkerEnum = new LinkerEnum(); + linkerEnum.setValue(name); + linker.setName(linkerEnum); + + // incremental, map + linker.setIncremental(incremental); + linker.setMap(map); + + // Add definitions (Window only) + if (os.equals(OS.WINDOWS) + && (type.equals(Library.SHARED) || type.equals(Library.JNI))) { + Set defs = new HashSet(); + try { + File cSrcDir = mojo.getC().getSourceDirectory(); + if (cSrcDir.exists()) + defs.addAll(FileUtils.getFiles(cSrcDir, "**/*.def", null)); + } catch (IOException e) { + } + try { + File cppSrcDir = mojo.getCpp().getSourceDirectory(); + if (cppSrcDir.exists()) + defs + .addAll(FileUtils.getFiles(cppSrcDir, "**/*.def", + null)); + } catch (IOException e) { + } + try { + File fortranSrcDir = mojo.getFortran().getSourceDirectory(); + if (fortranSrcDir.exists()) + defs.addAll(FileUtils.getFiles(fortranSrcDir, "**/*.def", + null)); + } catch (IOException e) { + } + + for (Iterator i = defs.iterator(); i.hasNext();) { + LinkerArgument arg = new LinkerArgument(); + arg.setValue("/def:" + (File) i.next()); + linker.addConfiguredLinkerArg(arg); + } + } + + // Add options to linker + if (options != null) { + for (Iterator i = options.iterator(); i.hasNext();) { + LinkerArgument arg = new LinkerArgument(); + arg.setValue((String) i.next()); + linker.addConfiguredLinkerArg(arg); + } + } + + if (optionSet != null) { + + String[] opts = optionSet.split("\\s"); + + for (int i = 0; i < opts.length; i++) { + + LinkerArgument arg = new LinkerArgument(); + + arg.setValue(opts[i]); + linker.addConfiguredLinkerArg(arg); + } + } + + if (!clearDefaultOptions) { + String options = NarUtil.getDefaults().getProperty( + prefix + "options"); + if (options != null) { + String[] option = options.split(" "); + for (int i = 0; i < option.length; i++) { + LinkerArgument arg = new LinkerArgument(); + arg.setValue(option[i]); + linker.addConfiguredLinkerArg(arg); + } + } + } + + // record the preference for nar dependency library link order + if (narDependencyLibOrder != null) { + + List libOrder = new LinkedList(); + + String[] libs = narDependencyLibOrder.split(","); + + for (int i = 0; i < libs.length; i++) { + libOrder.add(libs[i].trim()); + } + + mojo.setDependencyLibOrder(libOrder); + } + + // Add Libraries to linker + if ((libs != null) || (libSet != null)) { + + if (libs != null) { + + for (Iterator i = libs.iterator(); i.hasNext();) { + + Lib lib = (Lib) i.next(); + lib.addLibSet(mojo, linker, antProject); + } + } + + if (libSet != null) { + addLibraries(libSet, linker, antProject, false); + } + } + else { + + String libsList = NarUtil.getDefaults() + .getProperty(prefix + "libs"); + + addLibraries(libsList, linker, antProject, false); + } + + // Add System Libraries to linker + if ((sysLibs != null) || (sysLibSet != null)) { + + if (sysLibs != null) { + + for (Iterator i = sysLibs.iterator(); i.hasNext();) { + + SysLib sysLib = (SysLib) i.next(); + linker.addSyslibset(sysLib.getSysLibSet(antProject)); + } + } + + if (sysLibSet != null) { + addLibraries(sysLibSet, linker, antProject, true); + } + } + else { + + String sysLibsList = NarUtil.getDefaults().getProperty( + prefix + "sysLibs"); + + addLibraries(sysLibsList, linker, antProject, true); + } + + return linker; + } + + + private void addLibraries(String libraryList, LinkerDef linker, Project antProject, boolean isSystem) { + + if (libraryList == null) { + return; + } + + String[] lib = libraryList.split(","); + + for (int i = 0; i < lib.length; i++) { + + String[] libInfo = lib[i].trim().split(":", 3); + + LibrarySet librarySet = new LibrarySet(); + + if (isSystem) { + librarySet = new SystemLibrarySet(); + } + + librarySet.setProject(antProject); + librarySet.setLibs(new CUtil.StringArrayBuilder(libInfo[0])); + + if (libInfo.length > 1) { + + LibraryTypeEnum libType = new LibraryTypeEnum(); + + libType.setValue(libInfo[1]); + librarySet.setType(libType); + + if (!isSystem && (libInfo.length > 2)) { + librarySet.setDir(new File(libInfo[2])); + } + } + + if (!isSystem) { + linker.addLibset(librarySet); + } + else { + linker.addSyslibset((SystemLibrarySet)librarySet); + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarArchiver.java b/src/main/java/org/apache/maven/plugin/nar/NarArchiver.java new file mode 100644 index 0000000..a70a21c --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarArchiver.java @@ -0,0 +1,12 @@ +// Copyright FreeHEP, 2005. +package org.freehep.maven.nar; + +import org.codehaus.plexus.archiver.zip.AbstractZipArchiver; + +/** + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarArchiver.java eda4d0bbde3d 2007/07/03 16:52:10 duns $ + */ +public class NarArchiver extends AbstractZipArchiver { +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarArtifact.java b/src/main/java/org/apache/maven/plugin/nar/NarArtifact.java new file mode 100644 index 0000000..76850b5 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarArtifact.java @@ -0,0 +1,26 @@ +// Copyright 2006, FreeHEP. +package org.freehep.maven.nar; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; + +/** + * + * @author duns + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarArtifact.java eda4d0bbde3d 2007/07/03 16:52:10 duns $ + */ +public class NarArtifact extends DefaultArtifact { + + private NarInfo narInfo; + + public NarArtifact(Artifact dependency, NarInfo narInfo) { + super(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersionRange(), + dependency.getScope(), dependency.getType(), dependency.getClassifier(), + dependency.getArtifactHandler(), dependency.isOptional()); + this.narInfo = narInfo; + } + + public NarInfo getNarInfo() { + return narInfo; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarArtifactHandler.java b/src/main/java/org/apache/maven/plugin/nar/NarArtifactHandler.java new file mode 100644 index 0000000..60b55d2 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarArtifactHandler.java @@ -0,0 +1,39 @@ +// Copyright FreeHEP, 2007. +package org.freehep.maven.nar; + +import org.apache.maven.artifact.handler.ArtifactHandler; + +/** + * + * @author Mark Donszelmann + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarArtifactHandler.java 76e8ff7ad2b0 2007/07/24 04:15:54 duns $ + */ +public class NarArtifactHandler implements ArtifactHandler { + public String getPackaging() { + return "nar"; + } + + public String getClassifier() { + return null; + } + + public String getDirectory() { + return getExtension() + "s"; + } + + public String getExtension() { + return "jar"; + } + + public String getLanguage() { + return "java"; + } + + public boolean isAddedToClasspath() { + return true; + } + + public boolean isIncludesDependencies() { + return false; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarAssemblyMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarAssemblyMojo.java new file mode 100644 index 0000000..658d688 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarAssemblyMojo.java @@ -0,0 +1,99 @@ +// Copyright FreeHEP, 2006-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.util.FileUtils; + +/** + * Assemble libraries of NAR files. + * + * @goal nar-assembly + * @phase process-resources + * @requiresProject + * @requiresDependencyResolution + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarAssemblyMojo.java c867ab546be1 2007/07/05 21:26:30 duns $ + */ +public class NarAssemblyMojo extends AbstractDependencyMojo { + + /** + * List of classifiers which you want to assemble. Example ppc-MacOSX-g++-static, + * x86-Windows-msvc-shared, i386-Linux-g++-executable, .... + * + * @parameter expression="" + * @required + */ + private List classifiers; + + /** + * Copies the unpacked nar libraries and files into the projects target area + */ + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) { + getLog() + .info( + "***********************************************************************"); + getLog() + .info( + "NAR Assembly SKIPPED since no NAR libraries were built/downloaded."); + getLog() + .info( + "***********************************************************************"); + // NOTE: continue since the standard assemble mojo fails if we do + // not create the directories... + } + + for (Iterator j = classifiers.iterator(); j.hasNext();) { + String classifier = (String) j.next(); + + List narArtifacts = getNarManager().getNarDependencies("compile"); + List dependencies = getNarManager().getAttachedNarDependencies( + narArtifacts, classifier); + // this may make some extra copies... + for (Iterator d = dependencies.iterator(); d.hasNext();) { + Artifact dependency = (Artifact) d.next(); + getLog().debug("Assemble from " + dependency); + + // FIXME reported to maven developer list, isSnapshot + // changes behaviour + // of getBaseVersion, called in pathOf. + if (dependency.isSnapshot()) + ; + + File srcDir = new File(getLocalRepository().pathOf(dependency)); + srcDir = new File(getLocalRepository().getBasedir(), srcDir + .getParent()); + srcDir = new File(srcDir, "nar/"); + File dstDir = new File("target/nar/"); + try { + FileUtils.mkdir(dstDir.getPath()); + if (shouldSkip()) { + File note = new File(dstDir, "NAR_ASSEMBLY_SKIPPED"); + FileUtils + .fileWrite( + note.getPath(), + "The NAR Libraries of this distribution are missing because \n" + + "the NAR dependencies were not built/downloaded, presumably because\n" + + "the the distribution was built with the '-Dnar.skip=true' flag."); + } else { + getLog().debug("SrcDir: " + srcDir); + if (srcDir.exists()) { + FileUtils.copyDirectoryStructure(srcDir, dstDir); + } + } + } catch (IOException ioe) { + throw new MojoExecutionException( + "Failed to copy directory for dependency " + + dependency + " from "+srcDir+" to " + dstDir, ioe); + } + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarCompileMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarCompileMojo.java new file mode 100644 index 0000000..10db16e --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarCompileMojo.java @@ -0,0 +1,296 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import net.sf.antcontrib.cpptasks.CCTask; +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.LinkerDef; +import net.sf.antcontrib.cpptasks.OutputTypeEnum; +import net.sf.antcontrib.cpptasks.RuntimeType; +import net.sf.antcontrib.cpptasks.types.LibrarySet; +import net.sf.antcontrib.cpptasks.types.LinkerArgument; +import net.sf.antcontrib.cpptasks.types.SystemLibrarySet; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.StringUtils; + +/** + * Compiles native source files. + * + * @goal nar-compile + * @phase compile + * @requiresDependencyResolution compile + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarCompileMojo.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public class NarCompileMojo extends AbstractCompileMojo { + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) + return; + + // make sure destination is there + getTargetDirectory().mkdirs(); + + // check for source files + int noOfSources = 0; + noOfSources += getSourcesFor(getCpp()).size(); + noOfSources += getSourcesFor(getC()).size(); + noOfSources += getSourcesFor(getFortran()).size(); + if (noOfSources > 0) { + for (Iterator i = getLibraries().iterator(); i.hasNext();) { + createLibrary(getAntProject(), (Library) i.next()); + } + } + + try { + // FIXME, should the include paths be defined at a higher level ? + getCpp().copyIncludeFiles(getMavenProject(), + new File(getTargetDirectory(), "include")); + } catch (IOException e) { + throw new MojoExecutionException( + "NAR: could not copy include files", e); + } + } + + private List getSourcesFor(Compiler compiler) throws MojoFailureException { + try { + File srcDir = compiler.getSourceDirectory(); + return srcDir.exists() ? FileUtils.getFiles(srcDir, StringUtils + .join(compiler.getIncludes().iterator(), ","), null) + : Collections.EMPTY_LIST; + } catch (IOException e) { + return Collections.EMPTY_LIST; + } + } + + private void createLibrary(Project antProject, Library library) + throws MojoExecutionException, MojoFailureException { + // configure task + CCTask task = new CCTask(); + task.setProject(antProject); + + // set max cores + task.setMaxCores(getMaxCores(getAOL())); + + // outtype + OutputTypeEnum outTypeEnum = new OutputTypeEnum(); + String type = library.getType(); + outTypeEnum.setValue(type); + task.setOuttype(outTypeEnum); + + // stdc++ + task.setLinkCPP(library.linkCPP()); + + // fortran + task.setLinkFortran(library.linkFortran()); + + // outDir + File outDir = new File(getTargetDirectory(), type + .equals(Library.EXECUTABLE) ? "bin" : "lib"); + outDir = new File(outDir, getAOL().toString()); + if (!type.equals(Library.EXECUTABLE)) + outDir = new File(outDir, type); + outDir.mkdirs(); + + // outFile + File outFile; + if (type.equals(Library.EXECUTABLE)) { + // executable has no version number + outFile = new File(outDir, getMavenProject().getArtifactId()); + } else { + outFile = new File(outDir, getOutput(getAOL())); + } + getLog().debug("NAR - output: '" + outFile + "'"); + task.setOutfile(outFile); + + // object directory + File objDir = new File(getTargetDirectory(), "obj"); + objDir = new File(objDir, getAOL().toString()); + objDir.mkdirs(); + task.setObjdir(objDir); + + // failOnError, libtool + task.setFailonerror(failOnError(getAOL())); + task.setLibtool(useLibtool(getAOL())); + + // runtime + RuntimeType runtimeType = new RuntimeType(); + runtimeType.setValue(getRuntime(getAOL())); + task.setRuntime(runtimeType); + + // add C++ compiler + task.addConfiguredCompiler(getCpp().getCompiler(type, getOutput(getAOL()))); + + // add C compiler + task.addConfiguredCompiler(getC().getCompiler(type, getOutput(getAOL()))); + + // add Fortran compiler + task.addConfiguredCompiler(getFortran().getCompiler(type, getOutput(getAOL()))); + + // add javah include path + File jniDirectory = getJavah().getJniDirectory(); + if (jniDirectory.exists()) + task.createIncludePath().setPath(jniDirectory.getPath()); + + // add java include paths + getJava().addIncludePaths(task, type); + + // add dependency include paths + for (Iterator i = getNarManager().getNarDependencies("compile") + .iterator(); i.hasNext();) { + // FIXME, handle multiple includes from one NAR + NarArtifact narDependency = (NarArtifact) i.next(); + String binding = narDependency.getNarInfo().getBinding(getAOL(), + Library.STATIC); + getLog().debug( + "Looking for " + narDependency + " found binding " + + binding); + if (!binding.equals(Library.JNI)) { + File include = new File(getNarManager().getNarFile( + narDependency).getParentFile(), "nar/include"); + getLog().debug("Looking for for directory: " + include); + if (include.exists()) { + task.createIncludePath().setPath(include.getPath()); + } + } + } + + // add linker + LinkerDef linkerDefinition = getLinker().getLinker(this, antProject, + getOS(), getAOL().getKey() + ".linker.", type); + task.addConfiguredLinker(linkerDefinition); + + // add dependency libraries + // FIXME: what about PLUGIN and STATIC, depending on STATIC, should we + // not add all libraries, see NARPLUGIN-96 + if (type.equals(Library.SHARED) || type.equals(Library.JNI) || type.equals(Library.EXECUTABLE)) { + + List depLibOrder = getDependencyLibOrder(); + List depLibs = getNarManager().getNarDependencies("compile"); + + // reorder the libraries that come from the nar dependencies + // to comply with the order specified by the user + if ((depLibOrder != null) && !depLibOrder.isEmpty()) { + + List tmp = new LinkedList(); + + for (Iterator i = depLibOrder.iterator(); i.hasNext();) { + + String depToOrderName = (String)i.next(); + + for (Iterator j = depLibs.iterator(); j.hasNext();) { + + NarArtifact dep = (NarArtifact)j.next(); + String depName = dep.getGroupId() + ":" + dep.getArtifactId(); + + if (depName.equals(depToOrderName)) { + + tmp.add(dep); + j.remove(); + } + } + } + + tmp.addAll(depLibs); + depLibs = tmp; + } + + for (Iterator i = depLibs.iterator(); i.hasNext();) { + + NarArtifact dependency = (NarArtifact) i.next(); + + // FIXME no handling of "local" + + // FIXME, no way to override this at this stage + String binding = dependency.getNarInfo().getBinding(getAOL(), + Library.STATIC); + getLog().debug("Using Binding: " + binding); + AOL aol = getAOL(); + aol = dependency.getNarInfo().getAOL(getAOL()); + getLog().debug("Using Library AOL: " + aol.toString()); + + if (!binding.equals(Library.JNI)) { + File dir = new File(getNarManager().getNarFile(dependency) + .getParentFile(), "nar/lib/" + aol.toString() + "/" + binding); + getLog().debug("Looking for Library Directory: " + dir); + if (dir.exists()) { + LibrarySet libSet = new LibrarySet(); + libSet.setProject(antProject); + + // FIXME, no way to override + String libs = dependency.getNarInfo().getLibs(getAOL()); + if ((libs != null) && !libs.equals("")) { + getLog().debug("Using LIBS = " + libs); + libSet.setLibs(new CUtil.StringArrayBuilder(libs)); + libSet.setDir(dir); + task.addLibset(libSet); + } + } else { + getLog() + .debug( + "Library Directory " + dir + + " does NOT exist."); + } + + // FIXME, look again at this, for multiple dependencies we may need to remove duplicates + String options = dependency.getNarInfo().getOptions(getAOL()); + if ((options != null) && !options.equals("")) { + getLog().debug("Using OPTIONS = " + options); + LinkerArgument arg = new LinkerArgument(); + arg.setValue(options); + linkerDefinition.addConfiguredLinkerArg(arg); + } + + String sysLibs = dependency.getNarInfo().getSysLibs( + getAOL()); + if ((sysLibs != null) && !sysLibs.equals("")) { + getLog().debug("Using SYSLIBS = " + sysLibs); + SystemLibrarySet sysLibSet = new SystemLibrarySet(); + sysLibSet.setProject(antProject); + + sysLibSet + .setLibs(new CUtil.StringArrayBuilder(sysLibs)); + task.addSyslibset(sysLibSet); + } + } + } + } + + // Add JVM to linker + getJava().addRuntime(task, getJavaHome(getAOL()), getOS(), + getAOL().getKey() + "java."); + + // execute + try { + task.execute(); + } catch (BuildException e) { + throw new MojoExecutionException("NAR: Compile failed", e); + } + + // FIXME, this should be done in CPPTasks at some point + if (getRuntime(getAOL()).equals("dynamic") && + getOS().equals(OS.WINDOWS) && + getLinker().getName(null, null).equals("msvc") && + NarUtil.getEnv("MSVCVer", "MSVCVer", "6.0").startsWith("8.")) { + String libType = library.getType(); + if (libType.equals(Library.JNI) || libType.equals(Library.SHARED)) { + String dll = outFile.getPath()+".dll"; + String manifest = dll+".manifest"; + int result = NarUtil.runCommand("mt.exe", new String[] {"/manifest", manifest, "/outputresource:"+dll+";#2"}, null, getLog()); + if (result != 0) + throw new MojoFailureException("MT.EXE failed with exit code: " + result); + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarConstants.java b/src/main/java/org/apache/maven/plugin/nar/NarConstants.java new file mode 100644 index 0000000..2d80cd6 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarConstants.java @@ -0,0 +1,14 @@ +package org.freehep.maven.nar; + +public interface NarConstants { + public final static String NAR_EXTENSION = "nar"; + public final static String NAR_NO_ARCH = "noarch"; + public final static String NAR_ROLE_HINT = "nar-library"; + public final static String NAR_TYPE = "nar"; + + public final static int LOG_LEVEL_ERROR = 0; + public final static int LOG_LEVEL_WARNING = 1; + public final static int LOG_LEVEL_INFO = 2; + public final static int LOG_LEVEL_VERBOSE = 3; + public final static int LOG_LEVEL_DEBUG = 4; +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarDownloadMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarDownloadMojo.java new file mode 100644 index 0000000..f4830a8 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarDownloadMojo.java @@ -0,0 +1,72 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.util.Iterator; +import java.util.List; + +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +/** + * Downloads any dependent NAR files. This includes the noarch and aol type NAR files. + * + * @goal nar-download + * @phase generate-sources + * @requiresProject + * @requiresDependencyResolution + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarDownloadMojo.java c867ab546be1 2007/07/05 21:26:30 duns $ + */ +public class NarDownloadMojo extends AbstractDependencyMojo { + + /** + * Artifact resolver, needed to download source jars for inclusion in + * classpath. + * + * @component role="org.apache.maven.artifact.resolver.ArtifactResolver" + * @required + * @readonly + */ + private ArtifactResolver artifactResolver; + + /** + * Remote repositories which will be searched for source attachments. + * + * @parameter expression="${project.remoteArtifactRepositories}" + * @required + * @readonly + */ + private List remoteArtifactRepositories; + + /** + * List of classifiers which you want download. Example ppc-MacOSX-g++, + * x86-Windows-msvc, i386-Linux-g++. + * + * @parameter expression="" + */ + private List classifiers; + + public void execute() throws MojoExecutionException, MojoFailureException { + getLog().info("Using AOL: "+getAOL()); + + if (shouldSkip()) { + getLog().info("***********************************************************************"); + getLog().info("NAR Plugin SKIPPED, no NAR Libraries will be produced."); + getLog().info("***********************************************************************"); + + return; + } + + List narArtifacts = getNarManager().getNarDependencies("compile"); + if (classifiers == null) { + getNarManager().downloadAttachedNars(narArtifacts, remoteArtifactRepositories, + artifactResolver, null); + } else { + for (Iterator j = classifiers.iterator(); j.hasNext();) { + getNarManager().downloadAttachedNars(narArtifacts, remoteArtifactRepositories, + artifactResolver, (String) j.next()); + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarInfo.java b/src/main/java/org/apache/maven/plugin/nar/NarInfo.java new file mode 100644 index 0000000..b34d9b2 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarInfo.java @@ -0,0 +1,169 @@ +// Copyright FreeHEP, 2006-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.Properties; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.maven.plugin.logging.Log; + +/** + * + * @author Mark Donszelmann + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarInfo.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public class NarInfo { + + public static final String NAR_PROPERTIES = "nar.properties"; + private String groupId, artifactId, version; + private Properties info; + private Log log; + + public NarInfo(String groupId, String artifactId, String version, Log log) { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.log = log; + info = new Properties(); + + // Fill with general properties.nar file + File propertiesDir = new File("src/main/resources/META-INF/nar/" + + groupId + "/" + artifactId); + if (!propertiesDir.exists()) { + propertiesDir.mkdirs(); + } + File propertiesFile = new File(propertiesDir, NarInfo.NAR_PROPERTIES); + try { + info.load(new FileInputStream(propertiesFile)); + } catch (IOException ioe) { + // ignored + } + + } + + public String toString() { + StringBuffer s = new StringBuffer("NarInfo for "); + s.append(groupId); + s.append(":"); + s.append(artifactId); + s.append("-"); + s.append(version); + s.append(" {\n"); + + for (Iterator i = info.keySet().iterator(); i.hasNext();) { + String key = (String) i.next(); + s.append(" "); + s.append(key); + s.append("='"); + s.append(info.getProperty(key, "<null>")); + s.append("'\n"); + } + + s.append("}\n"); + return s.toString(); + } + + public boolean exists(JarFile jar) { + return getNarPropertiesEntry(jar) != null; + } + + public void read(JarFile jar) throws IOException { + info.load(jar.getInputStream(getNarPropertiesEntry(jar))); + } + + private JarEntry getNarPropertiesEntry(JarFile jar) { + return jar.getJarEntry("META-INF/nar/" + groupId + "/" + artifactId + + "/" + NAR_PROPERTIES); + } + + /** + * No binding means default binding. + * + * @param aol + * @return + */ + public String getBinding(AOL aol, String defaultBinding) { + return getProperty(aol, "libs.binding", defaultBinding); + } + + public void setBinding(AOL aol, String value) { + setProperty(aol, "libs.binding", value); + } + + // FIXME replace with list of AttachedNarArtifacts + public String[] getAttachedNars(AOL aol, String type) { + String attachedNars = getProperty(aol, "nar." + type); + return attachedNars != null ? attachedNars.split(",") : null; + } + + public void addNar(AOL aol, String type, String nar) { + String nars = getProperty(aol, "nar." + type); + nars = (nars == null) ? nar : nars + ", " + nar; + setProperty(aol, "nar." + type, nars); + } + + public void setNar(AOL aol, String type, String nar) { + setProperty(aol, "nar." + type, nar); + } + + public AOL getAOL(AOL aol) { + return aol == null ? null : new AOL(getProperty(aol, aol.toString(), aol.toString())); + } + + public String getOptions(AOL aol) { + return getProperty(aol, "linker.options"); + } + + public String getLibs(AOL aol) { + return getProperty(aol, "libs.names", artifactId + "-" + version); + } + + public String getSysLibs(AOL aol) { + return getProperty(aol, "syslibs.names"); + } + + public void writeToFile(File file) throws IOException { + info.store(new FileOutputStream((file)), "NAR Properties for " + + groupId + "." + artifactId + "-" + version); + } + + private void setProperty(AOL aol, String key, String value) { + if (aol == null) { + info.setProperty(key, value); + } else { + info.setProperty(aol.toString() + "." + key, value); + } + } + + public String getProperty(AOL aol, String key) { + return getProperty(aol, key, (String)null); + } + + public String getProperty(AOL aol, String key, String defaultValue) { + if (key == null) + return defaultValue; + String value = info.getProperty(key, defaultValue); + value = aol == null ? value : info.getProperty(aol.toString() + "." + + key, value); + log.debug("getProperty(" + aol + ", " + key + ", " + + defaultValue + ") = " + value); + return value; + } + + public int getProperty(AOL aol, String key, int defaultValue) { + return Integer.parseInt(getProperty(aol, key, Integer.toString(defaultValue))); + } + + public boolean getProperty(AOL aol, String key, boolean defaultValue) { + return Boolean.parseBoolean(getProperty(aol, key, String.valueOf(defaultValue))); + } + + public File getProperty(AOL aol, String key, File defaultValue) { + return new File(getProperty(aol, key, defaultValue.getPath())); + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarIntegrationTestMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarIntegrationTestMojo.java new file mode 100644 index 0000000..19884c2 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarIntegrationTestMojo.java @@ -0,0 +1,987 @@ +// Copied from Maven maven-surefire-plugin 2.3, 2006-2007 +package org.freehep.maven.nar; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.surefire.booter.ForkConfiguration; +import org.apache.maven.surefire.booter.SurefireBooter; +import org.apache.maven.surefire.booter.SurefireBooterForkException; +import org.apache.maven.surefire.booter.SurefireExecutionException; +import org.apache.maven.surefire.report.BriefConsoleReporter; +import org.apache.maven.surefire.report.BriefFileReporter; +import org.apache.maven.surefire.report.ConsoleReporter; +import org.apache.maven.surefire.report.DetailedConsoleReporter; +import org.apache.maven.surefire.report.FileReporter; +import org.apache.maven.surefire.report.ForkingConsoleReporter; +import org.apache.maven.surefire.report.XMLReporter; +import org.codehaus.plexus.util.StringUtils; + +/** + * Run integration tests using Surefire. + * + * This goal was copied from Maven's surefire plugin to accomodate a few things + * for the NAR plugin: 1. To test a jar file with its native module we can only + * run after the package phase, so we use the integration-test phase. 2. We need + * to set java.library.path to an AOL (architecture-os-linker) specific value, + * but AOL is only known in the NAR plugin and thus cannot be set from the pom. + * 3. To have the java.library.path definition picked up by java we need the + * "pertest" forkmode. + * + * To use this goal you need to put the test sources in the regular test + * directories but disable the running of the tests by the + * maven-surefire-plugin. + * + * @author Jason van Zyl (modified by Mark Donszelmann, noted by FREEHEP) + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarIntegrationTestMojo.java eeac31f37379 2007/07/24 04:02:00 duns $, + * 2.3 maven repository maven-surefire-plugin + * @requiresDependencyResolution test + * @goal nar-integration-test + * @phase integration-test + */ +// FREEHEP, changed class name, inheritence, goal and phase +public class NarIntegrationTestMojo extends AbstractCompileMojo { + // FREEHEP added test for JNI module + private boolean testJNIModule() { + for (Iterator i = getLibraries().iterator(); i.hasNext();) { + Library lib = (Library) i.next(); + if (lib.getType().equals(Library.JNI)) + return true; + } + return false; + } + + // FREEHEP added to get names + /** + * @parameter expression="${project}" + * @readonly + * @required + */ + private MavenProject project; + + // FREEHEP added because of naming conflict + /** + * Skip running of NAR plugins (any) altogether. + * + * @parameter expression="${nar.skip}" default-value="false" + */ + private boolean skipNAR; + + /** + * Set this to 'true' to bypass unit tests entirely. Its use is NOT + * RECOMMENDED, but quite convenient on occasion. + * + * @parameter expression="${maven.test.skip}" + */ + private boolean skip; + + /** + * Set this to 'true' to bypass unit tests execution, but still compile + * them. Its use is NOT RECOMMENDED, but quite convenient on occasion. + * + * @parameter expression="${maven.test.skip.exec}" + */ + private boolean skipExec; + + /** + * Set this to true to ignore a failure during testing. Its use is NOT + * RECOMMENDED, but quite convenient on occasion. + * + * @parameter expression="${maven.test.failure.ignore}" + */ + private boolean testFailureIgnore; + + /** + * The base directory of the project being tested. This can be obtained in + * your unit test by System.getProperty("basedir"). + * + * @parameter expression="${basedir}" + * @required + */ + private File basedir; + + // FIXME this field is not used + /** + * The directory containing generated classes of the project being tested. + * + * @parameter expression="${project.build.outputDirectory}" + * @required + */ + // FREEHEP + // private File classesDirectory; + /** + * The directory containing generated test classes of the project being + * tested. + * + * @parameter expression="${project.build.testOutputDirectory}" + * @required + */ + private File testClassesDirectory; + + /** + * The classpath elements of the project being tested. + * + * @parameter expression="${project.testClasspathElements}" + * @required + * @readonly + */ + private List classpathElements; + + /** + * Base directory where all reports are written to. + * + * @parameter expression="${project.build.directory}/surefire-reports" + */ + private File reportsDirectory; + + /** + * The test source directory containing test class sources. + * + * @parameter expression="${project.build.testSourceDirectory}" + * @required + */ + private File testSourceDirectory; + + /** + * Specify this parameter(can be a comma separated list) if you want to use + * the test pattern matching notation, Ant pattern matching, to select tests + * to run. The Ant pattern will be used to create an include pattern + * formatted like <code>**/${test}.java</code> When used, the + * <code>includes</code> and <code>excludes</code> patterns parameters + * are ignored. + * + * @parameter expression="${test}" + */ + private String test; + + /** + * List of patterns (separated by commas) used to specify the tests that + * should be included in testing. When not specified and when the + * <code>test</code> parameter is not specified, the default includes will + * be + * <code>**/Test*.java **/*Test.java **/*TestCase.java</code> + * + * @parameter + */ + private List includes; + + /** + * List of patterns (separated by commas) used to specify the tests that + * should be excluded in testing. When not specified and when the + * <code>test</code> parameter is not specified, the default excludes will + * be + * <code>**/Abstract*Test.java **/Abstract*TestCase.java **/*$*</code> + * + * @parameter + */ + private List excludes; + + /** + * ArtifactRepository of the localRepository. To obtain the directory of + * localRepository in unit tests use System.setProperty( "localRepository"). + * + * @parameter expression="${localRepository}" + * @required + * @readonly + */ + // FREEHEP removed, already in superclass + // private ArtifactRepository localRepository; + /** + * List of System properties to pass to the JUnit tests. + * + * @parameter + */ + private Properties systemProperties; + + /** + * Map of of plugin artifacts. + * + * @parameter expression="${plugin.artifactMap}" + * @required + * @readonly + */ + private Map pluginArtifactMap; + + /** + * Map of of project artifacts. + * + * @parameter expression="${project.artifactMap}" + * @required + * @readonly + */ + private Map projectArtifactMap; + + /** + * Option to print summary of test suites or just print the test cases that + * has errors. + * + * @parameter expression="${surefire.printSummary}" default-value="true" + */ + private boolean printSummary; + + /** + * Selects the formatting for the test report to be generated. Can be set as + * brief or plain. + * + * @parameter expression="${surefire.reportFormat}" default-value="brief" + */ + private String reportFormat; + + /** + * Option to generate a file test report or just output the test report to + * the console. + * + * @parameter expression="${surefire.useFile}" default-value="true" + */ + private boolean useFile; + + /** + * When forking, set this to true to redirect the unit test standard output + * to a file (found in reportsDirectory/testName-output.txt). + * + * @parameter expression="${maven.test.redirectTestOutputToFile}" + * default-value="false" + */ + private boolean redirectTestOutputToFile; + + /** + * Option to specify the forking mode. Can be "never", "once" or "always". + * "none" and "pertest" are also accepted for backwards compatibility. + * + * @parameter expression="${forkMode}" default-value="once" + */ + private String forkMode; + + /** + * Option to specify the jvm (or path to the java executable) to use with + * the forking options. For the default, the jvm will be the same as the one + * used to run Maven. + * + * @parameter expression="${jvm}" + */ + private String jvm; + + /** + * Arbitrary options to set on the command line. + * + * @parameter expression="${argLine}" + */ + private String argLine; + + /** + * Additional environments to set on the command line. + * + * @parameter + */ + private Map environmentVariables = new HashMap(); + + /** + * Command line working directory. + * + * @parameter + */ + private File workingDirectory; + + /** + * When false it makes tests run using the standard classloader delegation + * instead of the default Maven isolated classloader. Only used when forking + * (forkMode is not "none").<br/> Setting it to false helps with some + * problems caused by conflicts between xml parsers in the classpath and the + * Java 5 provider parser. + * + * @parameter expression="${childDelegation}" default-value="false" + */ + private boolean childDelegation; + + /** + * Groups for this test. Only classes/methods/etc decorated with one of the + * groups specified here will be included in test run, if specified. + * + * @parameter expression="${groups}" + */ + private String groups; + + /** + * Excluded groups. Any methods/classes/etc with one of the groups specified + * in this list will specifically not be run. + * + * @parameter expression="${excludedGroups}" + */ + private String excludedGroups; + + /** + * List of TestNG suite xml file locations, seperated by commas. It should + * be noted that if suiteXmlFiles is specified, <b>no</b> other tests will + * be run, ignoring other parameters, like includes and excludes. + * + * @parameter + */ + private File[] suiteXmlFiles; + + /** + * The attribute thread-count allows you to specify how many threads should + * be allocated for this execution. Only makes sense to use in conjunction + * with parallel. + * + * @parameter expression="${threadCount}" default-value="5" + */ + private int threadCount; + + /** + * When you use the parallel attribute, TestNG will try to run all your test + * methods in separate threads, except for methods that depend on each + * other, which will be run in the same thread in order to respect their + * order of execution. + * + * @parameter expression="${parallel}" default-value="false" + * @todo test how this works with forking, and console/file output + * parallelism + */ + private boolean parallel; + + /** + * Whether to trim the stack trace in the reports to just the lines within + * the test, or show the full trace. + * + * @parameter expression="${trimStackTrace}" default-value="true" + */ + private boolean trimStackTrace; + + /** + * Resolves the artifacts needed. + * + * @component + */ + private ArtifactResolver artifactResolver; + + /** + * Creates the artifact + * + * @component + */ + private ArtifactFactory artifactFactory; + + /** + * The plugin remote repositories declared in the pom. + * + * @parameter expression="${project.pluginArtifactRepositories}" + */ + private List remoteRepositories; + + /** + * For retrieval of artifact's metadata. + * + * @component + */ + private ArtifactMetadataSource metadataSource; + + private static final String BRIEF_REPORT_FORMAT = "brief"; + + private static final String PLAIN_REPORT_FORMAT = "plain"; + + private Properties originalSystemProperties; + + /** + * Flag to disable the generation of report files in xml format. + * + * @parameter expression="${disableXmlReport}" default-value="false" + */ + private boolean disableXmlReport; + + /** + * Option to pass dependencies to the system's classloader instead of using + * an isolated class loader when forking. Prevents problems with JDKs which + * implement the service provider lookup mechanism by using the system's + * classloader. + * + * @parameter expression="${surefire.useSystemClassLoader}" + * default-value="false" + */ + private boolean useSystemClassLoader; + + public void execute() throws MojoExecutionException, MojoFailureException { + if (verifyParameters()) { + SurefireBooter surefireBooter = constructSurefireBooter(); + + getLog().info("Surefire report directory: " + reportsDirectory); + + boolean success; + try { + success = surefireBooter.run(); + } catch (SurefireBooterForkException e) { + throw new MojoExecutionException(e.getMessage(), e); + } catch (SurefireExecutionException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + + if (originalSystemProperties != null) { + // restore system properties + System.setProperties(originalSystemProperties); + } + + if (!success) { + String msg = "There are test failures."; + + if (testFailureIgnore) { + getLog().error(msg); + } else { + throw new MojoFailureException(msg); + } + } + } + } + + private boolean verifyParameters() throws MojoFailureException { + // FREEHEP, shouldSkip() does not work... + if (skipNAR) { + getLog() + .info( + "***********************************************************************"); + getLog() + .info( + "NAR Integration Tests are SKIPPED since no NAR libraries were built."); + getLog() + .info( + "***********************************************************************"); + return false; + } + + if (skip || skipExec) { + getLog().info("Tests are skipped."); + return false; + } else if (!testClassesDirectory.exists()) { + getLog().info("No tests to run."); + return false; + } + + if (parallel) { + if (threadCount < 1) { + throw new MojoFailureException( + "Must have at least one thread in parallel mode"); + } + } + + if (useSystemClassLoader + && ForkConfiguration.FORK_NEVER.equals(forkMode)) { + getLog() + .warn( + "useSystemClassloader=true setting has no effect when not forking"); + } + + return true; + } + + private SurefireBooter constructSurefireBooter() + throws MojoExecutionException, MojoFailureException { + SurefireBooter surefireBooter = new SurefireBooter(); + + Artifact surefireArtifact = (Artifact) pluginArtifactMap + .get("org.apache.maven.surefire:surefire-booter"); + if (surefireArtifact == null) { + throw new MojoExecutionException( + "Unable to locate surefire-booter in the list of plugin artifacts"); + } + + surefireArtifact.isSnapshot(); // TODO: this is ridiculous, but it + // fixes getBaseVersion to be -SNAPSHOT + // if needed + + Artifact junitArtifact; + Artifact testNgArtifact; + try { + addArtifact(surefireBooter, surefireArtifact); + + junitArtifact = (Artifact) projectArtifactMap.get("junit:junit"); + + // TODO: this is pretty manual, but I'd rather not require the + // plugin > dependencies section right now + testNgArtifact = (Artifact) projectArtifactMap + .get("org.testng:testng"); + + if (testNgArtifact != null) { + addArtifact(surefireBooter, testNgArtifact); + + VersionRange range = VersionRange + .createFromVersionSpec("[4.7,)"); + if (!range.containsVersion(testNgArtifact.getSelectedVersion())) { + throw new MojoFailureException( + "TestNG support requires version 4.7 or above. You have declared version " + + testNgArtifact.getVersion()); + } + + // The plugin uses a JDK based profile to select the right + // testng. We might be explicity using a + // different one since its based on the source level, not the + // JVM. Prune using the filter. + addProvider(surefireBooter, "surefire-testng", surefireArtifact + .getBaseVersion(), testNgArtifact); + } else if (junitArtifact != null + && junitArtifact.getBaseVersion().startsWith("4")) { + addProvider(surefireBooter, "surefire-junit4", surefireArtifact + .getBaseVersion(), null); + } else { + // add the JUnit provider as default - it doesn't require JUnit + // to be present, + // since it supports POJO tests. + addProvider(surefireBooter, "surefire-junit", surefireArtifact + .getBaseVersion(), null); + } + } catch (ArtifactNotFoundException e) { + throw new MojoExecutionException( + "Unable to locate required surefire provider dependency: " + + e.getMessage(), e); + } catch (InvalidVersionSpecificationException e) { + throw new MojoExecutionException( + "Error determining the TestNG version requested: " + + e.getMessage(), e); + } catch (ArtifactResolutionException e) { + throw new MojoExecutionException( + "Error to resolving surefire provider dependency: " + + e.getMessage(), e); + } + + if (suiteXmlFiles != null && suiteXmlFiles.length > 0) { + if (testNgArtifact == null) { + throw new MojoExecutionException( + "suiteXmlFiles is configured, but there is no TestNG dependency"); + } + for (int i = 0; i < suiteXmlFiles.length; i++) { + File file = suiteXmlFiles[i]; + if (file.exists()) { + surefireBooter + .addTestSuite( + "org.apache.maven.surefire.testng.TestNGXmlTestSuite", + new Object[] { + file, + testSourceDirectory + .getAbsolutePath() }); + } + } + } else { + List includes; + List excludes; + + if (test != null) { + // Check to see if we are running a single test. The raw + // parameter will + // come through if it has not been set. + + // FooTest -> **/FooTest.java + + includes = new ArrayList(); + + excludes = new ArrayList(); + + String[] testRegexes = StringUtils.split(test, ","); + + for (int i = 0; i < testRegexes.length; i++) { + includes.add("**/" + testRegexes[i] + ".java"); + } + } else { + includes = this.includes; + + excludes = this.excludes; + + // defaults here, qdox doesn't like the end javadoc value + // Have to wrap in an ArrayList as surefire expects an ArrayList + // instead of a List for some reason + if (includes == null || includes.size() == 0) { + includes = new ArrayList(Arrays.asList(new String[] { + "**/Test*.java", "**/*Test.java", + "**/*TestCase.java" })); + } + if (excludes == null || excludes.size() == 0) { + excludes = new ArrayList(Arrays.asList(new String[] { + "**/Abstract*Test.java", + "**/Abstract*TestCase.java", "**/*$*" })); + } + } + + if (testNgArtifact != null) { + surefireBooter + .addTestSuite( + "org.apache.maven.surefire.testng.TestNGDirectoryTestSuite", + new Object[] { testClassesDirectory, includes, + excludes, groups, excludedGroups, + Boolean.valueOf(parallel), + new Integer(threadCount), + testSourceDirectory.getAbsolutePath() }); + } else { + String junitDirectoryTestSuite; + // FREEHEP NP check + if (junitArtifact != null + && junitArtifact.getBaseVersion().startsWith("4")) { + junitDirectoryTestSuite = "org.apache.maven.surefire.junit4.JUnit4DirectoryTestSuite"; + } else { + junitDirectoryTestSuite = "org.apache.maven.surefire.junit.JUnitDirectoryTestSuite"; + } + + // fall back to JUnit, which also contains POJO support. Also it + // can run + // classes compiled against JUnit since it has a dependency on + // JUnit itself. + surefireBooter + .addTestSuite(junitDirectoryTestSuite, new Object[] { + testClassesDirectory, includes, excludes }); + } + } + + // ---------------------------------------------------------------------- + // + // ---------------------------------------------------------------------- + + getLog().debug("Test Classpath :"); + + // no need to add classes/test classes directory here - they are in the + // classpath elements already + + for (Iterator i = classpathElements.iterator(); i.hasNext();) { + String classpathElement = (String) i.next(); + + getLog().debug(" " + classpathElement); + + surefireBooter.addClassPathUrl(classpathElement); + } + + // ---------------------------------------------------------------------- + // Forking + // ---------------------------------------------------------------------- + + ForkConfiguration fork = new ForkConfiguration(); + + // FREEHEP + if (project.getPackaging().equals("nar") + || (getNarManager().getNarDependencies("test").size() > 0)) + forkMode = "pertest"; + + fork.setForkMode(forkMode); + + processSystemProperties(!fork.isForking()); + + if (getLog().isDebugEnabled()) { + showMap(systemProperties, "system property"); + } + + if (fork.isForking()) { + fork.setSystemProperties(systemProperties); + + if (jvm == null || "".equals(jvm)) { + // use the same JVM as the one used to run Maven (the + // "java.home" one) + jvm = System.getProperty("java.home") + File.separator + "bin" + + File.separator + "java"; + getLog().debug("Using JVM: " + jvm); + } + + fork.setJvmExecutable(jvm); + + if (workingDirectory != null) { + fork.setWorkingDirectory(workingDirectory); + } else { + fork.setWorkingDirectory(basedir); + } + + // BEGINFREEHEP + if (argLine == null) + argLine = ""; + + StringBuffer javaLibraryPath = new StringBuffer(); + if (testJNIModule()) { + // Add libraries to java.library.path for testing + File jniLibraryPathEntry = new File(project.getBasedir(), + "target/nar/lib/" + getAOL() + "/jni"); + if (jniLibraryPathEntry.exists()) { + getLog().debug( + "Adding library directory to java.library.path: " + + jniLibraryPathEntry); + if (javaLibraryPath.length() > 0) + javaLibraryPath.append(File.pathSeparator); + javaLibraryPath.append(jniLibraryPathEntry); + } + + File sharedLibraryPathEntry = new File(project.getBasedir(), + "target/nar/lib/" + getAOL() + "/shared"); + if (sharedLibraryPathEntry.exists()) { + getLog().debug( + "Adding library directory to java.library.path: " + + sharedLibraryPathEntry); + if (javaLibraryPath.length() > 0) + javaLibraryPath.append(File.pathSeparator); + javaLibraryPath.append(sharedLibraryPathEntry); + } + + // add jar file to classpath, as one may want to read a + // properties file for artifactId and version + String jarFile = "target/" + project.getArtifactId() + "-" + + project.getVersion() + ".jar"; + getLog().debug("Adding to surefire test classpath: " + jarFile); + surefireBooter.addClassPathUrl(jarFile); + } + + List dependencies = getNarManager().getNarDependencies("test"); + for (Iterator i = dependencies.iterator(); i.hasNext();) { + NarArtifact dependency = (NarArtifact) i.next(); + // FIXME this should be overridable + // NarInfo info = dependency.getNarInfo(); + // String binding = info.getBinding(getAOL(), Library.STATIC); + // NOTE: fixed to shared, jni + String[] bindings = { Library.SHARED, Library.JNI }; + for (int j = 0; j < bindings.length; j++) { + String binding = bindings[j]; + if (!binding.equals(Library.STATIC)) { + File depLibPathEntry = new File(getNarManager() + .getNarFile(dependency).getParent(), "nar/lib/" + + getAOL() + "/" + binding); + if (depLibPathEntry.exists()) { + getLog().debug( + "Adding dependency directory to java.library.path: " + + depLibPathEntry); + if (javaLibraryPath.length() > 0) + javaLibraryPath.append(File.pathSeparator); + javaLibraryPath.append(depLibPathEntry); + } + } + } + } + + // add final javalibrary path + if (javaLibraryPath.length() > 0) { + // NOTE java.library.path only works for the jni lib itself, and + // not for its dependent shareables. + // NOTE: java.library.path does not work with arguments with + // spaces as + // SureFireBooter splits the line in parts and then quotes + // it wrongly + NarUtil.addLibraryPathToEnv(javaLibraryPath.toString(), environmentVariables, getOS()); + } + + // necessary to find WinSxS + if (getOS().equals(OS.WINDOWS)) { + environmentVariables.put("SystemRoot", NarUtil.getEnv("SystemRoot", "SystemRoot", "C:\\Windows")); + } + // ENDFREEHEP + + fork.setArgLine(argLine); + + fork.setEnvironmentVariables(environmentVariables); + + if (getLog().isDebugEnabled()) { + showMap(environmentVariables, "environment variable"); + + fork.setDebug(true); + } + } + + surefireBooter.setRedirectTestOutputToFile(redirectTestOutputToFile); + + surefireBooter.setForkConfiguration(fork); + + surefireBooter.setChildDelegation(childDelegation); + + surefireBooter.setReportsDirectory(reportsDirectory); + + surefireBooter.setUseSystemClassLoader(useSystemClassLoader); + + addReporters(surefireBooter, fork.isForking()); + + return surefireBooter; + } + + private void showMap(Map map, String setting) { + for (Iterator i = map.keySet().iterator(); i.hasNext();) { + String key = (String) i.next(); + String value = (String) map.get(key); + getLog().debug( + "Setting " + setting + " [" + key + "]=[" + value + "]"); + } + } + + private void addProvider(SurefireBooter surefireBooter, String provider, + String version, Artifact filteredArtifact) + throws ArtifactNotFoundException, ArtifactResolutionException { + Artifact providerArtifact = artifactFactory.createDependencyArtifact( + "org.apache.maven.surefire", provider, VersionRange + .createFromVersion(version), "jar", null, + Artifact.SCOPE_TEST); + ArtifactResolutionResult result = resolveArtifact(filteredArtifact, + providerArtifact); + + for (Iterator i = result.getArtifacts().iterator(); i.hasNext();) { + Artifact artifact = (Artifact) i.next(); + + getLog().debug( + "Adding to surefire test classpath: " + + artifact.getFile().getAbsolutePath()); + + surefireBooter.addSurefireClassPathUrl(artifact.getFile() + .getAbsolutePath()); + } + } + + private ArtifactResolutionResult resolveArtifact(Artifact filteredArtifact, + Artifact providerArtifact) throws ArtifactResolutionException, + ArtifactNotFoundException { + ArtifactFilter filter = null; + if (filteredArtifact != null) { + filter = new ExcludesArtifactFilter(Collections + .singletonList(filteredArtifact.getGroupId() + ":" + + filteredArtifact.getArtifactId())); + } + + Artifact originatingArtifact = artifactFactory.createBuildArtifact( + "dummy", "dummy", "1.0", "jar"); + + // FREEHEP, use access method rather than "localRepository" field. + return artifactResolver.resolveTransitively(Collections + .singleton(providerArtifact), originatingArtifact, + getLocalRepository(), remoteRepositories, metadataSource, + filter); + } + + private void addArtifact(SurefireBooter surefireBooter, + Artifact surefireArtifact) throws ArtifactNotFoundException, + ArtifactResolutionException { + ArtifactResolutionResult result = resolveArtifact(null, + surefireArtifact); + + for (Iterator i = result.getArtifacts().iterator(); i.hasNext();) { + Artifact artifact = (Artifact) i.next(); + + getLog().debug( + "Adding to surefire booter test classpath: " + + artifact.getFile().getAbsolutePath()); + + surefireBooter.addSurefireBootClassPathUrl(artifact.getFile() + .getAbsolutePath()); + } + } + + protected void processSystemProperties(boolean setInSystem) { + if (systemProperties == null) { + systemProperties = new Properties(); + } + + originalSystemProperties = (Properties) System.getProperties().clone(); + + systemProperties.setProperty("basedir", basedir.getAbsolutePath()); + + // FREEHEP, use access method rather than "localRepository" field. + systemProperties.setProperty("localRepository", getLocalRepository() + .getBasedir()); + + if (setInSystem) { + // Add all system properties configured by the user + Iterator iter = systemProperties.keySet().iterator(); + + while (iter.hasNext()) { + String key = (String) iter.next(); + + String value = systemProperties.getProperty(key); + + System.setProperty(key, value); + } + } + } + + /** + * <p> + * Adds Reporters that will generate reports with different formatting. + * <p> + * The Reporter that will be added will be based on the value of the + * parameter useFile, reportFormat, and printSummary. + * + * @param surefireBooter + * The surefire booter that will run tests. + * @param forking + */ + private void addReporters(SurefireBooter surefireBooter, boolean forking) { + Boolean trimStackTrace = Boolean.valueOf(this.trimStackTrace); + if (useFile) { + if (printSummary) { + if (forking) { + surefireBooter.addReport(ForkingConsoleReporter.class + .getName(), new Object[] { trimStackTrace }); + } else { + surefireBooter.addReport(ConsoleReporter.class.getName(), + new Object[] { trimStackTrace }); + } + } + + if (BRIEF_REPORT_FORMAT.equals(reportFormat)) { + surefireBooter.addReport(BriefFileReporter.class.getName(), + new Object[] { reportsDirectory, trimStackTrace }); + } else if (PLAIN_REPORT_FORMAT.equals(reportFormat)) { + surefireBooter.addReport(FileReporter.class.getName(), + new Object[] { reportsDirectory, trimStackTrace }); + } + } else { + if (BRIEF_REPORT_FORMAT.equals(reportFormat)) { + surefireBooter.addReport(BriefConsoleReporter.class.getName(), + new Object[] { trimStackTrace }); + } else if (PLAIN_REPORT_FORMAT.equals(reportFormat)) { + surefireBooter.addReport(DetailedConsoleReporter.class + .getName(), new Object[] { trimStackTrace }); + } + } + + if (!disableXmlReport) { + surefireBooter.addReport(XMLReporter.class.getName(), new Object[] { + reportsDirectory, trimStackTrace }); + } + } + + /** + * @return SurefirePlugin Returns the skipExec. + */ + public boolean isSkipExec() { + return this.skipExec; + } + + /** + * @param skipExec + * the skipExec to set + */ + public void setSkipExec(boolean skipExec) { + this.skipExec = skipExec; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarJavahMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarJavahMojo.java new file mode 100644 index 0000000..582e0ad --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarJavahMojo.java @@ -0,0 +1,24 @@ +// Copyright FreeHEP, 2005. +package org.freehep.maven.nar; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +/** + * Compiles class files into c/c++ headers using "javah". + * Any class file that contains methods that were declared + * "native" will be run through javah. + * + * @goal nar-javah + * @phase compile + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarJavahMojo.java eeac31f37379 2007/07/24 04:02:00 duns $ + */ +public class NarJavahMojo extends AbstractCompileMojo { + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) return; + + getJavah().execute(); + } +}
\ No newline at end of file diff --git a/src/main/java/org/apache/maven/plugin/nar/NarLogger.java b/src/main/java/org/apache/maven/plugin/nar/NarLogger.java new file mode 100644 index 0000000..9836808 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarLogger.java @@ -0,0 +1,76 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import org.apache.maven.plugin.logging.Log; +import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.BuildListener; +import org.apache.tools.ant.Project; + +/** + * Logger to connect the Ant logging to the Maven logging. + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarLogger.java 9589202406dd 2007/07/23 17:42:54 duns $ + */ +public class NarLogger implements BuildListener { + + private Log log; + + public NarLogger(Log log) { + this.log = log; + } + + public void buildStarted(BuildEvent event) { + } + + public void buildFinished(BuildEvent event) { + } + + public void targetStarted(BuildEvent event) { + } + + public void targetFinished(BuildEvent event) { + } + + public void taskStarted(BuildEvent event) { + } + + public void taskFinished(BuildEvent event) { + } + + public void messageLogged(BuildEvent event) { + String msg = event.getMessage(); + switch (event.getPriority()) { + case Project.MSG_ERR: + if (msg.indexOf("ar: creating archive") >= 0) { + log.debug(msg); + } else if (msg.indexOf("warning") >= 0) { + log.warn(msg); + } else { + log.error(msg); + } + break; + case Project.MSG_WARN: + log.warn(msg); + break; + case Project.MSG_INFO: + if ((msg.indexOf("files were compiled") >= 0) || (msg.indexOf("Linking...") >= 0)) { + log.info(msg); + } else if (msg.indexOf("error") >= 0) { + log.error(msg); + } else if (msg.indexOf("warning") >= 0) { + log.warn(msg); + } else { + log.debug(msg); + } + break; + case Project.MSG_VERBOSE: + log.debug(msg); + break; + default: + case Project.MSG_DEBUG: + log.debug(msg); + break; + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarManager.java b/src/main/java/org/apache/maven/plugin/nar/NarManager.java new file mode 100644 index 0000000..16dda1d --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarManager.java @@ -0,0 +1,363 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.LinkedList; +import java.util.jar.JarFile; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.archiver.ArchiverException; +import org.codehaus.plexus.archiver.UnArchiver; +import org.codehaus.plexus.archiver.manager.ArchiverManager; +import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; +import org.codehaus.plexus.util.FileUtils; + +public class NarManager { + + private Log log; + + private MavenProject project; + + private ArtifactRepository repository; + + private AOL defaultAOL; + private String linkerName; + + private String[] narTypes = { "noarch", Library.STATIC, Library.SHARED, Library.JNI, Library.PLUGIN }; + + public NarManager(Log log, ArtifactRepository repository, + MavenProject project, String architecture, String os, Linker linker) + throws MojoFailureException { + this.log = log; + this.repository = repository; + this.project = project; + this.defaultAOL = NarUtil.getAOL(architecture, os, linker, null); + this.linkerName = NarUtil.getLinkerName(architecture, os, linker); + } + + /** + * Returns dependencies which are dependent on NAR files (i.e. contain + * NarInfo) + */ + public List/* <NarArtifact> */getNarDependencies(String scope) + throws MojoExecutionException { + List narDependencies = new LinkedList(); + for (Iterator i = getDependencies(scope).iterator(); i.hasNext();) { + Artifact dependency = (Artifact) i.next(); + log.debug("Examining artifact for NarInfo: "+dependency); + + NarInfo narInfo = getNarInfo(dependency); + if (narInfo != null) { + log.debug(" - added as NarDependency"); + narDependencies.add(new NarArtifact(dependency, narInfo)); + } + } + return narDependencies; + } + + /** + * Returns all NAR dependencies by type: noarch, static, dynamic, jni, + * plugin. + * + * @throws MojoFailureException + */ + public Map/* <String, List<AttachedNarArtifact>> */getAttachedNarDependencyMap( + String scope) throws MojoExecutionException, MojoFailureException { + Map attachedNarDependencies = new HashMap(); + for (Iterator i = getNarDependencies(scope).iterator(); i.hasNext();) { + Artifact dependency = (Artifact) i.next(); + for (int j = 0; j < narTypes.length; j++) { + List artifactList = getAttachedNarDependencies(dependency, + defaultAOL, narTypes[j]); + if (artifactList != null) + attachedNarDependencies.put(narTypes[j], artifactList); + } + } + return attachedNarDependencies; + } + + public List/* <AttachedNarArtifact> */getAttachedNarDependencies( + List/* <NarArtifacts> */narArtifacts) + throws MojoExecutionException, MojoFailureException { + return getAttachedNarDependencies(narArtifacts, null); + } + + public List/* <AttachedNarArtifact> */getAttachedNarDependencies( + List/* <NarArtifacts> */narArtifacts, String classifier) + throws MojoExecutionException, MojoFailureException { + AOL aol = null; + String type = null; + if (classifier != null) { + int dash = classifier.lastIndexOf('-'); + if (dash < 0) { + aol = new AOL(classifier); + type = null; + } else { + aol = new AOL(classifier.substring(0, dash)); + type = classifier.substring(dash + 1); + } + } + return getAttachedNarDependencies(narArtifacts, aol, type); + } + + /** + * Returns a list of all attached nar dependencies for a specific binding + * and "noarch", but not where "local" is specified + * + * @param scope + * compile, test, runtime, .... + * @param aol + * either a valid aol, noarch or null. In case of null both the + * default getAOL() and noarch dependencies are returned. + * @param type + * noarch, static, shared, jni, or null. In case of null the + * default binding found in narInfo is used. + * @return + * @throws MojoExecutionException + * @throws MojoFailureException + */ + public List/* <AttachedNarArtifact> */getAttachedNarDependencies( + List/* <NarArtifacts> */narArtifacts, AOL aol, String type) + throws MojoExecutionException, MojoFailureException { + boolean noarch = false; + if (aol == null) { + noarch = true; + aol = defaultAOL; + } + + List artifactList = new ArrayList(); + for (Iterator i = narArtifacts.iterator(); i.hasNext();) { + Artifact dependency = (Artifact) i.next(); + NarInfo narInfo = getNarInfo(dependency); + if (noarch) { + artifactList.addAll(getAttachedNarDependencies(dependency, + null, "noarch")); + } + + // use preferred binding, unless non existing. + String binding = narInfo.getBinding(aol, type != null ? type + : "static"); + + // FIXME kludge, but does not work anymore since AOL is now a class + if (aol.equals("noarch")) { + // FIXME no handling of local + artifactList.addAll(getAttachedNarDependencies(dependency, + null, "noarch")); + } else { + artifactList.addAll(getAttachedNarDependencies(dependency, aol, + binding)); + } + } + return artifactList; + } + + private List/* <AttachedNarArtifact> */getAttachedNarDependencies( + Artifact dependency, AOL aol, String type) + throws MojoExecutionException, MojoFailureException { + log.debug("GetNarDependencies for " + dependency + ", aol: " + aol + ", type: " + type); + List artifactList = new ArrayList(); + NarInfo narInfo = getNarInfo(dependency); + String[] nars = narInfo.getAttachedNars(aol, type); + // FIXME Move this to NarInfo.... + if (nars != null) { + for (int j = 0; j < nars.length; j++) { + log.debug(" Checking: " + nars[j]); + if (nars[j].equals("")) + continue; + String[] nar = nars[j].split(":", 5); + if (nar.length >= 4) { + try { + String groupId = nar[0].trim(); + String artifactId = nar[1].trim(); + String ext = nar[2].trim(); + String classifier = nar[3].trim(); + // translate for instance g++ to gcc... + aol = narInfo.getAOL(aol); + if (aol != null) { + classifier = NarUtil.replace("${aol}", aol.toString(), + classifier); + } + String version = nar.length >= 5 ? nar[4].trim() + : dependency.getVersion(); + artifactList.add(new AttachedNarArtifact(groupId, + artifactId, version, dependency.getScope(), + ext, classifier, dependency.isOptional())); + } catch (InvalidVersionSpecificationException e) { + throw new MojoExecutionException( + "Error while reading nar file for dependency " + + dependency, e); + } + } else { + log.warn("nars property in " + dependency.getArtifactId() + + " contains invalid field: '" + nars[j] + + "' for type: " + type); + } + } + } + return artifactList; + } + + public NarInfo getNarInfo(Artifact dependency) + throws MojoExecutionException { + // FIXME reported to maven developer list, isSnapshot changes behaviour + // of getBaseVersion, called in pathOf. + if (dependency.isSnapshot()) + ; + + File file = new File(repository.getBasedir(), repository + .pathOf(dependency)); + JarFile jar = null; + try { + jar = new JarFile(file); + NarInfo info = new NarInfo(dependency.getGroupId(), dependency + .getArtifactId(), dependency.getVersion(), log); + if (!info.exists(jar)) + return null; + info.read(jar); + return info; + } catch (IOException e) { + throw new MojoExecutionException("Error while reading " + file, e); + } finally { + if (jar != null) { + try { + jar.close(); + } catch (IOException e) { + // ignore + } + } + } + } + + public File getNarFile(Artifact dependency) throws MojoFailureException { + // FIXME reported to maven developer list, isSnapshot changes behaviour + // of getBaseVersion, called in pathOf. + if (dependency.isSnapshot()) + ; + return new File(repository.getBasedir(), NarUtil.replace("${aol}", + defaultAOL.toString(), repository.pathOf(dependency))); + } + + private List getDependencies(String scope) { + if (scope.equals("test")) { + return project.getTestArtifacts(); + } else if (scope.equals("runtime")) { + return project.getRuntimeArtifacts(); + } + return project.getCompileArtifacts(); + } + + public void downloadAttachedNars(List/* <NarArtifacts> */narArtifacts, + List remoteRepositories, ArtifactResolver resolver, + String classifier) throws MojoExecutionException, + MojoFailureException { + // FIXME this may not be the right way to do this.... -U ignored and + // also SNAPSHOT not used + List dependencies = getAttachedNarDependencies(narArtifacts, classifier); + for (Iterator i = dependencies.iterator(); i.hasNext();) { + Artifact dependency = (Artifact) i.next(); + try { + log.debug("Resolving " + dependency); + resolver.resolve(dependency, remoteRepositories, repository); + } catch (ArtifactNotFoundException e) { + String message = "nar not found " + dependency.getId(); + throw new MojoExecutionException(message, e); + } catch (ArtifactResolutionException e) { + String message = "nar cannot resolve " + dependency.getId(); + throw new MojoExecutionException(message, e); + } + } + } + + public void unpackAttachedNars(List/* <NarArtifacts> */narArtifacts, + ArchiverManager manager, String classifier, String os) + throws MojoExecutionException, MojoFailureException { + log.debug("Unpack called for OS: "+os+", classifier: "+classifier+" for NarArtifacts {"); + for (Iterator i = narArtifacts.iterator(); i.hasNext(); ) { + log.debug(" - "+((NarArtifact)i.next())); + } + log.debug("}"); + // FIXME, kludge to get to download the -noarch, based on classifier + List dependencies = getAttachedNarDependencies(narArtifacts, classifier); + for (Iterator i = dependencies.iterator(); i.hasNext();) { + Artifact dependency = (Artifact) i.next(); + log.debug("Unpack " + dependency); + File file = getNarFile(dependency); + File narLocation = new File(file.getParentFile(), "nar"); + File flagFile = new File(narLocation, FileUtils.basename(file + .getPath(), "." + AbstractNarMojo.NAR_EXTENSION) + + ".flag"); + + boolean process = false; + if (!narLocation.exists()) { + narLocation.mkdirs(); + process = true; + } else if (!flagFile.exists()) { + process = true; + } else if (file.lastModified() > flagFile.lastModified()) { + process = true; + } + + if (process) { + try { + unpackNar(manager, file, narLocation); + if (!NarUtil.getOS(os).equals("Windows")) { + NarUtil.makeExecutable(new File(narLocation, "bin/"+defaultAOL), + log); + // FIXME clumsy + if (defaultAOL.hasLinker("g++")) { + NarUtil.makeExecutable(new File(narLocation, "bin/"+NarUtil.replace("g++", "gcc", defaultAOL.toString())), + log); + } + } + if (linkerName.equals("gcc") || linkerName.equals("g++")) { + NarUtil.runRanlib(new File(narLocation, "lib/"+defaultAOL), log); + // FIXME clumsy + if (defaultAOL.hasLinker("g++")) { + NarUtil.runRanlib(new File(narLocation, "lib/"+NarUtil.replace("g++", "gcc", defaultAOL.toString())), + log); + } + } + FileUtils.fileDelete(flagFile.getPath()); + FileUtils.fileWrite(flagFile.getPath(), ""); + } catch (IOException e) { + log.warn("Cannot create flag file: " + flagFile.getPath()); + } + } + } + } + + private void unpackNar(ArchiverManager manager, File file, File location) + throws MojoExecutionException { + try { + UnArchiver unArchiver; + unArchiver = manager.getUnArchiver(AbstractNarMojo.NAR_ROLE_HINT); + unArchiver.setSourceFile(file); + unArchiver.setDestDirectory(location); + unArchiver.extract(); + } catch (IOException e) { + throw new MojoExecutionException("Error unpacking file: " + file + + " to: " + location, e); + } catch (NoSuchArchiverException e) { + throw new MojoExecutionException("Error unpacking file: " + file + + " to: " + location, e); + } catch (ArchiverException e) { + throw new MojoExecutionException("Error unpacking file: " + file + + " to: " + location, e); + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarPackageMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarPackageMojo.java new file mode 100644 index 0000000..1009679 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarPackageMojo.java @@ -0,0 +1,135 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProjectHelper; +import org.codehaus.plexus.archiver.Archiver; +import org.codehaus.plexus.archiver.ArchiverException; +import org.codehaus.plexus.archiver.zip.ZipArchiver; + +/** + * Jars up the NAR files. + * + * @goal nar-package + * @phase package + * @requiresProject + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarPackageMojo.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public class NarPackageMojo extends AbstractCompileMojo { + + /** + * Used for attaching the artifact in the project + * + * @component + */ + private MavenProjectHelper projectHelper; + + private File narDirectory; + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) + return; + + // FIX for NARPLUGIN-??? where -DupdateReleaseInfo copies to a .nar file + getMavenProject().getArtifact().setArtifactHandler( + new NarArtifactHandler()); + + narDirectory = new File(getOutputDirectory(), "nar"); + + // noarch + String include = "include"; + if (new File(narDirectory, include).exists()) { + attachNar("include", null, NAR_NO_ARCH); + } + + // create nar with binaries + String bin = "bin"; + String[] binAOLs = new File(narDirectory, bin).list(); + for (int i = 0; i < (binAOLs != null ? binAOLs.length : 0); i++) { + attachNar(bin + "/" + binAOLs[i], binAOLs[i], bin); + } + + // create nars for each type of library (static, shared). + String bindingType = null; + for (Iterator i = getLibraries().iterator(); i.hasNext();) { + Library library = (Library) i.next(); + String type = library.getType(); + if (bindingType == null) + bindingType = type; + + // create nar with libraries + String lib = "lib"; + String[] libAOLs = new File(narDirectory, lib).list(); + for (int j = 0; j < (libAOLs != null ? libAOLs.length : 0); j++) { + attachNar(lib + "/" + libAOLs[j] + "/" + type, libAOLs[j], type); + } + } + + // override binding if not set + if (getNarInfo().getBinding(null, null) == null) { + getNarInfo().setBinding(null, bindingType != null ? bindingType + : Library.NONE); + } + + try { + File propertiesDir = new File(getOutputDirectory(), "classes/META-INF/nar/" + + getMavenProject().getGroupId() + "/" + getMavenProject().getArtifactId()); + if (!propertiesDir.exists()) { + propertiesDir.mkdirs(); + } + File propertiesFile = new File(propertiesDir, NarInfo.NAR_PROPERTIES); + getNarInfo().writeToFile(propertiesFile); + } catch (IOException ioe) { + throw new MojoExecutionException( + "Cannot write nar properties file", ioe); + } + } + + private void attachNar(String dir, String aol, String type) + throws MojoExecutionException { + File libFile = new File(getOutputDirectory(), getFinalName() + "-" + + (aol != null ? aol + "-" : "") + type + "." + NAR_EXTENSION); + nar(libFile, narDirectory, new String[] { dir }); + projectHelper.attachArtifact(getMavenProject(), NAR_TYPE, + (aol != null ? aol + "-" : "") + type, libFile); + getNarInfo().setNar(null, type, getMavenProject().getGroupId() + ":" + + getMavenProject().getArtifactId() + ":" + NAR_TYPE + ":" + + (aol != null ? "${aol}-" : "") + type); + + } + + private void nar(File nar, File dir, String[] dirs) + throws MojoExecutionException { + try { + if (nar.exists()) { + nar.delete(); + } + + Archiver archiver = new ZipArchiver(); + // seems to return same archiver all the time + // archiverManager.getArchiver(NAR_ROLE_HINT); + for (int i = 0; i < dirs.length; i++) { + String[] includes = new String[] { dirs[i] + "/**" }; + archiver.addDirectory(dir, includes, null); + } + archiver.setDestFile(nar); + archiver.createArchive(); + } catch (ArchiverException e) { + throw new MojoExecutionException( + "Error while creating NAR archive.", e); + // } catch (NoSuchArchiverException e) { + // throw new MojoExecutionException("Error while creating NAR + // archive.", e ); + } catch (IOException e) { + throw new MojoExecutionException( + "Error while creating NAR archive.", e); + } + } + +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarResourcesMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarResourcesMojo.java new file mode 100644 index 0000000..ee4d712 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarResourcesMojo.java @@ -0,0 +1,162 @@ +// Copyright FreeHEP, 2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.archiver.ArchiverException; +import org.codehaus.plexus.archiver.UnArchiver; +import org.codehaus.plexus.archiver.manager.ArchiverManager; +import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.SelectorUtils; + +/** + * Copies any resources, including AOL specific distributions, to the target + * area for packaging + * + * @goal nar-resources + * @phase process-resources + * @requiresProject + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarResourcesMojo.java 2126b860c9c5 2007/07/31 23:19:30 duns $ + */ +public class NarResourcesMojo extends AbstractCompileMojo { + + /** + * Directory for nar resources. Defaults to src/nar/resources + * + * @parameter expression="${basedir}/src/nar/resources" + * @required + */ + private File resourceDirectory; + + /** + * Binary directory (relative to ${resourceDirectory}/aol/${aol} + * + * @parameter expression="bin" + * @required + */ + private String resourceBinDir; + + /** + * Include directory (relative to ${resourceDirectory}/aol/${aol} + * + * @parameter expression="include" + * @required + */ + private String resourceIncludeDir; + + /** + * Library directory (relative to ${resourceDirectory}/aol/${aol} + * + * @parameter expression="lib" + * @required + */ + private String resourceLibDir; + + /** + * To look up Archiver/UnArchiver implementations + * + * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}" + * @required + */ + private ArchiverManager archiverManager; + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) + return; + + // scan for AOLs + File aolDir = new File(resourceDirectory, "aol"); + if (aolDir.exists()) { + String[] aols = aolDir.list(); + for (int i = 0; i < aols.length; i++) { + boolean ignore = false; + for (Iterator j = FileUtils.getDefaultExcludesAsList() + .iterator(); j.hasNext();) { + String exclude = (String)j.next(); + if (SelectorUtils.matchPath(exclude.replace('/', File.separatorChar), aols[i])) { + ignore = true; + break; + } + } + if (!ignore) { + copyResources(new File(aolDir, aols[i])); + } + } + } + } + + private void copyResources(File aolDir) throws MojoExecutionException, + MojoFailureException { + String aol = aolDir.getName(); + int copied = 0; + try { + // copy headers + File includeDir = new File(aolDir, resourceIncludeDir); + if (includeDir.exists()) { + File includeDstDir = new File(getTargetDirectory(), "include"); + copied += NarUtil.copyDirectoryStructure(includeDir, + includeDstDir, null, NarUtil.DEFAULT_EXCLUDES); + } + + // copy binaries + File binDir = new File(aolDir, resourceBinDir); + if (binDir.exists()) { + File binDstDir = new File(getTargetDirectory(), "bin"); + binDstDir = new File(binDstDir, aol); + + copied += NarUtil.copyDirectoryStructure(binDir, binDstDir, + null, NarUtil.DEFAULT_EXCLUDES); + } + + // copy libraries + File libDir = new File(aolDir, resourceLibDir); + if (libDir.exists()) { + // create all types of libs + for (Iterator i = getLibraries().iterator(); i.hasNext();) { + Library library = (Library) i.next(); + String type = library.getType(); + File libDstDir = new File(getTargetDirectory(), "lib"); + libDstDir = new File(libDstDir, aol); + libDstDir = new File(libDstDir, type); + + // filter files for lib + String includes = "**/*." + + NarUtil.getDefaults().getProperty( + NarUtil.getAOLKey(aol) + "." + type + + ".extension"); + copied += NarUtil.copyDirectoryStructure(libDir, libDstDir, + includes, NarUtil.DEFAULT_EXCLUDES); + } + } + + // unpack jar files + File classesDirectory = new File(getOutputDirectory(),"classes"); + classesDirectory.mkdirs(); + List jars = FileUtils.getFiles(aolDir, "**/*.jar", null); + for (Iterator i=jars.iterator(); i.hasNext(); ) { + File jar = (File)i.next(); + getLog().debug("Unpacking jar "+jar); + UnArchiver unArchiver; + unArchiver = archiverManager.getUnArchiver(AbstractNarMojo.NAR_ROLE_HINT); + unArchiver.setSourceFile(jar); + unArchiver.setDestDirectory(classesDirectory); + unArchiver.extract(); + } + } catch (IOException e) { + throw new MojoExecutionException("NAR: Could not copy resources", e); + } catch (NoSuchArchiverException e) { + throw new MojoExecutionException("NAR: Could not find archiver", e); + } catch (ArchiverException e) { + throw new MojoExecutionException("NAR: Could not unarchive jar file", e); + } + getLog().info("Copied " + copied + " resources for " + aol); + } + +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarSystemGenerate.java b/src/main/java/org/apache/maven/plugin/nar/NarSystemGenerate.java new file mode 100644 index 0000000..f1d9e7e --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarSystemGenerate.java @@ -0,0 +1,79 @@ +// Copyright FreeHEP, 2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Iterator; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +/** + * Generates a NarSystem class with static methods to use inside the java part + * of the library. + * + * @goal nar-system-generate + * @phase generate-sources + * @requiresProject + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarSystemGenerate.java d43b38443d0b 2007/09/13 18:31:01 duns $ + */ +public class NarSystemGenerate extends AbstractCompileMojo { + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) + return; + + // get packageName if specified for JNI. + String packageName = null; + String narSystemName = null; + File narSystemDirectory = null; + for (Iterator i = getLibraries().iterator(); i.hasNext() + && (packageName == null);) { + Library library = (Library) i.next(); + if (library.getType().equals(Library.JNI)) { + packageName = library.getNarSystemPackage(); + narSystemName = library.getNarSystemName(); + narSystemDirectory = library.getNarSystemDirectory(); + } + } + + if (packageName == null) + return; + + // make sure destination is there + narSystemDirectory.mkdirs(); + + getMavenProject().addCompileSourceRoot(narSystemDirectory.getPath()); + + File fullDir = new File(narSystemDirectory, packageName.replace('.', '/')); + fullDir.mkdirs(); + + File narSystem = new File(fullDir, narSystemName + ".java"); + try { + FileOutputStream fos = new FileOutputStream(narSystem); + PrintWriter p = new PrintWriter(fos); + p.println("// DO NOT EDIT: Generated by NarSystemGenerate."); + p.println("package " + packageName + ";"); + p.println(""); + p.println("public class NarSystem {"); + p.println(""); + p.println(" private NarSystem() {"); + p.println(" }"); + p.println(""); + p.println(" public static void loadLibrary() {"); + p.println(" System.loadLibrary(\"" + + getMavenProject().getArtifactId() + "-" + + getMavenProject().getVersion() + "\");"); + p.println(" }"); + p.println("}"); + p.close(); + fos.close(); + } catch (IOException e) { + throw new MojoExecutionException("Could not write '" + + narSystemName + "'", e); + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarTestCompileMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarTestCompileMojo.java new file mode 100644 index 0000000..e55a4ad --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarTestCompileMojo.java @@ -0,0 +1,225 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import net.sf.antcontrib.cpptasks.CCTask; +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.OutputTypeEnum; +import net.sf.antcontrib.cpptasks.RuntimeType; +import net.sf.antcontrib.cpptasks.types.LibrarySet; +import net.sf.antcontrib.cpptasks.types.LibraryTypeEnum; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; + +/** + * Compiles native test source files. + * + * @goal nar-testCompile + * @phase test-compile + * @requiresDependencyResolution test + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarTestCompileMojo.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public class NarTestCompileMojo extends AbstractCompileMojo { + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) + return; + + // make sure destination is there + getTargetDirectory().mkdirs(); + + for (Iterator i = getTests().iterator(); i.hasNext();) { + createTest(getAntProject(), (Test) i.next()); + } + } + + private void createTest(Project antProject, Test test) + throws MojoExecutionException, MojoFailureException { + String type = "test"; + + // configure task + CCTask task = new CCTask(); + task.setProject(antProject); + + // outtype + OutputTypeEnum outTypeEnum = new OutputTypeEnum(); + outTypeEnum.setValue(Library.EXECUTABLE); + task.setOuttype(outTypeEnum); + + // outDir + File outDir = new File(getTargetDirectory(), "bin"); + outDir = new File(outDir, getAOL().toString()); + outDir.mkdirs(); + + // outFile + File outFile = new File(outDir, test.getName()); + getLog().debug("NAR - output: '" + outFile + "'"); + task.setOutfile(outFile); + + // object directory + File objDir = new File(getTargetDirectory(), "obj"); + objDir = new File(objDir, getAOL().toString()); + objDir.mkdirs(); + task.setObjdir(objDir); + + // failOnError, libtool + task.setFailonerror(failOnError(getAOL())); + task.setLibtool(useLibtool(getAOL())); + + // runtime + RuntimeType runtimeType = new RuntimeType(); + runtimeType.setValue(getRuntime(getAOL())); + task.setRuntime(runtimeType); + + // add C++ compiler + task.addConfiguredCompiler(getCpp().getCompiler(type, test.getName())); + + // add C compiler + task.addConfiguredCompiler(getC().getCompiler(type, test.getName())); + + // add Fortran compiler + task.addConfiguredCompiler(getFortran().getCompiler(type, + test.getName())); + + // add java include paths + getJava().addIncludePaths(task, type); + + // add dependency include paths + for (Iterator i = getNarManager().getNarDependencies("test").iterator(); i + .hasNext();) { + File include = new File(getNarManager().getNarFile( + (Artifact) i.next()).getParentFile(), "nar/include"); + if (include.exists()) { + task.createIncludePath().setPath(include.getPath()); + } + } + + // add linker + task.addConfiguredLinker(getLinker().getLinker(this, antProject, + getOS(), getAOL().getKey() + "linker.", type)); + + // FIXME hardcoded values + String libName = getFinalName(); + File includeDir = new File(getMavenProject().getBuild().getDirectory(), + "nar/include"); + File libDir = new File(getMavenProject().getBuild().getDirectory(), + "nar/lib/" + getAOL() + "/" + test.getLink()); + + // copy shared library + // FIXME why do we do this ? +/* Removed in alpha-10 + if (test.getLink().equals(Library.SHARED)) { + try { + // defaults are Unix + String libPrefix = NarUtil.getDefaults().getProperty( + getAOLKey() + "shared.prefix", "lib"); + String libExt = NarUtil.getDefaults().getProperty( + getAOLKey() + "shared.extension", "so"); + File copyDir = new File(getTargetDirectory(), (getOS().equals( + "Windows") ? "bin" : "lib") + + "/" + getAOL() + "/" + test.getLink()); + FileUtils.copyFileToDirectory(new File(libDir, libPrefix + + libName + "." + libExt), copyDir); + if (!getOS().equals(OS.WINDOWS)) { + libDir = copyDir; + } + } catch (IOException e) { + throw new MojoExecutionException( + "NAR: Could not copy shared library", e); + } + } +*/ + // FIXME what about copying the other shared libs? + + // add include of this package + if (includeDir.exists()) { + task.createIncludePath().setLocation(includeDir); + } + + // add library of this package + if (libDir.exists()) { + LibrarySet libSet = new LibrarySet(); + libSet.setProject(antProject); + libSet.setLibs(new CUtil.StringArrayBuilder(libName)); + LibraryTypeEnum libType = new LibraryTypeEnum(); + libType.setValue(test.getLink()); + libSet.setType(libType); + libSet.setDir(libDir); + task.addLibset(libSet); + } + + // add dependency libraries + List depLibOrder = getDependencyLibOrder(); + List depLibs = getNarManager().getNarDependencies("test"); + + // reorder the libraries that come from the nar dependencies + // to comply with the order specified by the user + if ((depLibOrder != null) && !depLibOrder.isEmpty()) { + + List tmp = new LinkedList(); + + for (Iterator i = depLibOrder.iterator(); i.hasNext();) { + + String depToOrderName = (String)i.next(); + + for (Iterator j = depLibs.iterator(); j.hasNext();) { + + NarArtifact dep = (NarArtifact)j.next(); + String depName = dep.getGroupId() + ":" + dep.getArtifactId(); + + if (depName.equals(depToOrderName)) { + + tmp.add(dep); + j.remove(); + } + } + } + + tmp.addAll(depLibs); + depLibs = tmp; + } + + for (Iterator i = depLibs.iterator(); i.hasNext();) { + + Artifact dependency = (Artifact) i.next(); + // FIXME: this should be preferred binding + File lib = new File(getNarManager().getNarFile(dependency) + .getParentFile(), "nar/lib/" + getAOL() + "/" + + test.getLink()); + if (lib.exists()) { + LibrarySet libset = new LibrarySet(); + libset.setProject(antProject); + libset.setLibs(new CUtil.StringArrayBuilder(dependency + .getArtifactId() + + "-" + dependency.getVersion())); + libset.setDir(lib); + task.addLibset(libset); + } + } + + // Add JVM to linker + getJava().addRuntime(task, getJavaHome(getAOL()), getOS(), + getAOL().getKey() + ".java."); + + // execute + try { + task.execute(); + } catch (BuildException e) { + throw new MojoExecutionException("NAR: Test-Compile failed", e); + } + } + + protected File getTargetDirectory() { + return new File(getMavenProject().getBuild().getDirectory(), "test-nar"); + } + +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarTestMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarTestMojo.java new file mode 100644 index 0000000..62e721e --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarTestMojo.java @@ -0,0 +1,148 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.StringUtils; + +/** + * Tests NAR files. Runs Native Tests and executables if produced. + * + * @goal nar-test + * @phase test + * @requiresProject + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarTestMojo.java 51709c87671c 2007/08/08 22:49:17 duns $ + */ +public class NarTestMojo extends AbstractCompileMojo { + + /** + * The classpath elements of the project being tested. + * + * @parameter expression="${project.testClasspathElements}" + * @required + * @readonly + */ + private List classpathElements; + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) + return; + + // run all tests + for (Iterator i = getTests().iterator(); i.hasNext();) { + runTest((Test) i.next()); + } + + for (Iterator i = getLibraries().iterator(); i.hasNext();) { + runExecutable((Library) i.next()); + } + } + + private void runTest(Test test) throws MojoExecutionException, + MojoFailureException { + // run if requested + if (test.shouldRun()) { + String name = "target/test-nar/bin/" + getAOL() + "/" + test.getName(); + getLog().info("Running " + name); + List args = test.getArgs(); + int result = NarUtil.runCommand(getMavenProject() + .getBasedir() + + "/" + name, (String[]) args.toArray(new String[args.size()]), generateEnvironment(test, + getLog()), getLog()); + if (result != 0) + throw new MojoFailureException("Test " + name + + " failed with exit code: " + result+" 0x"+Integer.toHexString(result)); + } + } + + private void runExecutable(Library library) throws MojoExecutionException, + MojoFailureException { + if (library.getType().equals(Library.EXECUTABLE) && library.shouldRun()) { + MavenProject project = getMavenProject(); + String name = "target/nar/bin/" + getAOL() + "/" + + project.getArtifactId(); + getLog().info("Running " + name); + List args = library.getArgs(); + int result = NarUtil.runCommand(project.getBasedir() + + "/" + name, (String[]) args.toArray(new String[args.size()]), generateEnvironment( + library, getLog()), getLog()); + if (result != 0) + throw new MojoFailureException("Test " + name + + " failed with exit code: " + result+" 0x"+Integer.toHexString(result)); + } + } + + protected File getTargetDirectory() { + return new File(getMavenProject().getBuild().getDirectory(), "test-nar"); + } + + private String[] generateEnvironment(Executable exec, Log log) + throws MojoExecutionException, MojoFailureException { + List env = new ArrayList(); + + Set/*<File>*/ sharedPaths = new HashSet(); + + // add all shared libraries of this package + for (Iterator i=getLibraries().iterator(); i.hasNext(); ) { + Library lib = (Library)i.next(); + if (lib.getType().equals(Library.SHARED)) { + sharedPaths.add(new File(getMavenProject().getBasedir(), "target/nar/lib/"+getAOL()+"/"+lib.getType())); + } + } + + // add dependent shared libraries + String classifier = getAOL()+"-shared"; + List narArtifacts = getNarManager().getNarDependencies("compile"); + List dependencies = getNarManager().getAttachedNarDependencies( + narArtifacts, classifier); + for (Iterator d = dependencies.iterator(); d.hasNext();) { + Artifact dependency = (Artifact) d.next(); + getLog().debug("Looking for dependency " + dependency); + + // FIXME reported to maven developer list, isSnapshot + // changes behaviour + // of getBaseVersion, called in pathOf. + if (dependency.isSnapshot()) + ; + + File libDir = new File(getLocalRepository().pathOf(dependency)); + libDir = new File(getLocalRepository().getBasedir(), libDir + .getParent()); + libDir = new File(libDir, "nar/lib/"+getAOL()+"/shared"); + sharedPaths.add(libDir); + } + + // set environment + if (sharedPaths.size() > 0) { + String sharedPath = ""; + for (Iterator i=sharedPaths.iterator(); i.hasNext(); ) { + sharedPath += ((File)i.next()).getPath(); + if (i.hasNext()) sharedPath += File.pathSeparator; + } + + String sharedEnv = NarUtil.addLibraryPathToEnv(sharedPath, null, getOS()); + env.add(sharedEnv); + } + + // necessary to find WinSxS + if (getOS().equals(OS.WINDOWS)) { + env.add("SystemRoot="+NarUtil.getEnv("SystemRoot", "SystemRoot", "C:\\Windows")); + } + + // add CLASSPATH + env.add("CLASSPATH="+StringUtils.join(classpathElements.iterator(), File.pathSeparator)); + + return env.size() > 0 ? (String[]) env.toArray(new String[env.size()]) : null; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarUnArchiver.java b/src/main/java/org/apache/maven/plugin/nar/NarUnArchiver.java new file mode 100644 index 0000000..7a94d60 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarUnArchiver.java @@ -0,0 +1,12 @@ +// Copyright FreeHEP, 2005. +package org.freehep.maven.nar; + +import org.codehaus.plexus.archiver.zip.AbstractZipUnArchiver; + +/** + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarUnArchiver.java eda4d0bbde3d 2007/07/03 16:52:10 duns $ + */ +public class NarUnArchiver extends AbstractZipUnArchiver { +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarUnpackMojo.java b/src/main/java/org/apache/maven/plugin/nar/NarUnpackMojo.java new file mode 100644 index 0000000..eb6b1db --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarUnpackMojo.java @@ -0,0 +1,52 @@ +// Copyright FreeHEP, 2005-2006. +package org.freehep.maven.nar; + +import java.util.Iterator; +import java.util.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.archiver.manager.ArchiverManager; + +/** + * Unpacks NAR files. Unpacking happens in the local repository, + * and also sets flags on binaries and corrects static libraries. + * + * @goal nar-unpack + * @phase process-sources + * @requiresProject + * @requiresDependencyResolution + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarUnpackMojo.java eda4d0bbde3d 2007/07/03 16:52:10 duns $ + */ +public class NarUnpackMojo extends AbstractDependencyMojo { + + /** + * List of classifiers which you want unpack. Example ppc-MacOSX-g++, + * x86-Windows-msvc, i386-Linux-g++. + * + * @parameter expression="" + */ + private List classifiers; + + /** + * To look up Archiver/UnArchiver implementations + * + * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}" + * @required + */ + private ArchiverManager archiverManager; + + public void execute() throws MojoExecutionException, MojoFailureException { + if (shouldSkip()) return; + + List narArtifacts = getNarManager().getNarDependencies("compile"); + if (classifiers == null) { + getNarManager().unpackAttachedNars(narArtifacts, archiverManager, null, getOS()); + } else { + for (Iterator j = classifiers.iterator(); j.hasNext();) { + getNarManager().unpackAttachedNars(narArtifacts, archiverManager, (String) j.next(), getOS()); + } + } + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/NarUtil.java b/src/main/java/org/apache/maven/plugin/nar/NarUtil.java new file mode 100644 index 0000000..c5372b9 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/NarUtil.java @@ -0,0 +1,417 @@ +// Copyright 2005-2007, FreeHEP. +package org.freehep.maven.nar; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Pattern; + +import org.apache.bcel.classfile.ClassFormatException; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.JavaClass; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.PropertyUtils; +import org.codehaus.plexus.util.cli.Commandline; + +/** + * @author Mark Donszelmann + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/NarUtil.java 0ee9148b7c6a 2007/09/20 18:42:29 duns $ + */ +public class NarUtil { + + private static Properties defaults; + + public static Properties getDefaults() throws MojoFailureException { + // read properties file with defaults + if (defaults == null) { + defaults = PropertyUtils.loadProperties(NarUtil.class + .getResourceAsStream("aol.properties")); + } + if (defaults == null) + throw new MojoFailureException( + "NAR: Could not load default properties file: 'aol.properties'."); + + return defaults; + } + + public static String getOS(String os) { + // adjust OS if not given + if (os == null) { + os = System.getProperty("os.name"); + if (os.startsWith("Windows")) + os = OS.WINDOWS; + if (os.startsWith("windows")) + os = OS.WINDOWS; + if (os.equals("Mac OS X")) + os = OS.MACOSX; + } + return os; + } + + public static String getArchitecture(String architecture) { + return architecture; + } + + public static Linker getLinker(Linker linker) { + if (linker == null) { + linker = new Linker(); + } + return linker; + } + + public static String getLinkerName(String architecture, String os, + Linker linker) throws MojoFailureException { + return getLinker(linker).getName(getDefaults(), + getArchitecture(architecture) + "." + getOS(os) + "."); + } + + public static AOL getAOL(String architecture, String os, Linker linker, + String aol) throws MojoFailureException { + // adjust aol + return aol == null ? new AOL(getArchitecture(architecture), getOS(os), + getLinkerName(architecture, os, linker)) : new AOL(aol); + } + + // FIXME, should go to AOL. + public static String getAOLKey(String architecture, String os, Linker linker) + throws MojoFailureException { + // construct AOL key prefix + return getArchitecture(architecture) + "." + getOS(os) + "." + + getLinkerName(architecture, os, linker) + "."; + } + + public static String getAOLKey(String aol) { + // FIXME, this may not always work correctly + return replace("-", ".", aol); + } + + public static File getJavaHome(File javaHome, String os) { + // adjust JavaHome + if (javaHome == null) { + javaHome = new File(System.getProperty("java.home")); + if (!getOS(os).equals("MacOSX")) { + javaHome = new File(javaHome, ".."); + } + } + return javaHome; + } + + public static void makeExecutable(File file, final Log log) + throws MojoExecutionException, MojoFailureException { + if (!file.exists()) + return; + + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + makeExecutable(files[i], log); + } + } + if (file.isFile() && file.canRead() && file.canWrite() + && !file.isHidden()) { + // chmod +x file + int result = runCommand("chmod", new String[] { "+x", + file.getPath() }, null, log); + if (result != 0) { + throw new MojoExecutionException("Failed to execute 'chmod +x " + + file.getPath() + "'" + " return code: \'" + result + + "\'."); + } + } + } + + public static void runRanlib(File file, final Log log) + throws MojoExecutionException, MojoFailureException { + if (!file.exists()) { + return; + } + + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + runRanlib(files[i], log); + } + } + if (file.isFile() && file.canRead() && file.canWrite() + && !file.isHidden() && file.getName().endsWith(".a")) { + // ranlib file + int result = runCommand("ranlib", new String[] { file.getPath() }, + null, log); + if (result != 0) { + throw new MojoExecutionException("Failed to execute 'ranlib " + + file.getPath() + "'" + " return code: \'" + result + + "\'."); + } + } + } + + /** + * Returns the Bcel Class corresponding to the given class filename + * + * @param filename + * the absolute file name of the class + * @return the Bcel Class. + * @throws IOException, + * ClassFormatException + */ + public static final JavaClass getBcelClass(String filename) + throws IOException, ClassFormatException { + ClassParser parser = new ClassParser(filename); + return parser.parse(); + } + + /** + * Returns the header file name (javah) corresponding to the given class + * file name + * + * @param filename + * the absolute file name of the class + * @return the header file name. + */ + public static final String getHeaderName(String base, String filename) { + base = base.replaceAll("\\\\", "/"); + filename = filename.replaceAll("\\\\", "/"); + if (!filename.startsWith(base)) { + throw new IllegalArgumentException("Error " + filename + + " does not start with " + base); + } + String header = filename.substring(base.length() + 1); + header = header.replaceAll("/", "_"); + header = header.replaceAll("\\.class", ".h"); + return header; + } + + /** + * Replaces target with replacement in string. For jdk 1.4 compatiblity. + * + * @param target + * @param replacement + * @param string + * @return + */ + public static String replace(CharSequence target, CharSequence replacement, + String string) { + return Pattern.compile(quote(target.toString())/* + * , Pattern.LITERAL jdk + * 1.4 + */).matcher(string).replaceAll( + /* Matcher. jdk 1.4 */quoteReplacement(replacement.toString())); + } + + /* for jdk 1.4 */ + private static String quote(String s) { + int slashEIndex = s.indexOf("\\E"); + if (slashEIndex == -1) + return "\\Q" + s + "\\E"; + + StringBuffer sb = new StringBuffer(s.length() * 2); + sb.append("\\Q"); + slashEIndex = 0; + int current = 0; + while ((slashEIndex = s.indexOf("\\E", current)) != -1) { + sb.append(s.substring(current, slashEIndex)); + current = slashEIndex + 2; + sb.append("\\E\\\\E\\Q"); + } + sb.append(s.substring(current, s.length())); + sb.append("\\E"); + return sb.toString(); + } + + /* for jdk 1.4 */ + private static String quoteReplacement(String s) { + if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1)) + return s; + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '\\') { + sb.append('\\'); + sb.append('\\'); + } else if (c == '$') { + sb.append('\\'); + sb.append('$'); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + public static final String DEFAULT_EXCLUDES = "**/*~,**/#*#,**/.#*,**/%*%,**/._*," + + "**/CVS,**/CVS/**,**/.cvsignore," + + "**/SCCS,**/SCCS/**,**/vssver.scc," + + "**/.svn,**/.svn/**,**/.DS_Store"; + + public static int copyDirectoryStructure(File sourceDirectory, + File destinationDirectory, String includes, String excludes) + throws IOException { + if (!sourceDirectory.exists()) { + throw new IOException("Source directory doesn't exists (" + + sourceDirectory.getAbsolutePath() + ")."); + } + + List files = FileUtils.getFiles(sourceDirectory, includes, excludes); + String sourcePath = sourceDirectory.getAbsolutePath(); + + int copied = 0; + for (Iterator i = files.iterator(); i.hasNext();) { + File file = (File) i.next(); + String dest = file.getAbsolutePath(); + dest = dest.substring(sourcePath.length() + 1); + File destination = new File(destinationDirectory, dest); + if (file.isFile()) { + destination = destination.getParentFile(); + FileUtils.copyFileToDirectory(file, destination); + copied++; + } else if (file.isDirectory()) { + if (!destination.exists() && !destination.mkdirs()) { + throw new IOException( + "Could not create destination directory '" + + destination.getAbsolutePath() + "'."); + } + copied += copyDirectoryStructure(file, destination, includes, + excludes); + } else { + throw new IOException("Unknown file type: " + + file.getAbsolutePath()); + } + } + return copied; + } + + public static String getEnv(String envKey, String alternateSystemProperty, + String defaultValue) { + String envValue = null; + try { + envValue = System.getenv(envKey); + if (envValue == null && alternateSystemProperty != null) { + envValue = System.getProperty(alternateSystemProperty); + } + } catch (Error e) { + // JDK 1.4? + if (alternateSystemProperty != null) { + envValue = System.getProperty(alternateSystemProperty); + } + } + + if (envValue == null) { + envValue = defaultValue; + } + + return envValue; + } + + public static String addLibraryPathToEnv(String path, Map environment, + String os) { + String pathName = null; + char separator = ' '; + if (os.equals(OS.WINDOWS)) { + pathName = "PATH"; + separator = ';'; + } else if (os.equals(OS.MACOSX)) { + pathName = "DYLD_LIBRARY_PATH"; + separator = ':'; + } else { + pathName = "LD_LIBRARY_PATH"; + separator = ':'; + } + + String value = environment != null ? (String) environment.get(pathName) + : null; + if (value == null) { + value = NarUtil.getEnv(pathName, pathName, null); + } + + path = path.replace(File.pathSeparatorChar, separator); + if (value != null) { + value += separator + path; + } else { + value = path; + } + if (environment != null) { + environment.put(pathName, value); + } + return pathName + "=" + value; + } + + public static int runCommand(String cmd, String[] args, String[] env, + Log log) throws MojoExecutionException, MojoFailureException { + log.debug("RunCommand: " + cmd); + Commandline cmdLine = new Commandline(); + cmdLine.setExecutable(cmd); + if (args != null) { + for (int i = 0; i < args.length; i++) { + log.debug(" '" + args[i] + "'"); + } + cmdLine.addArguments(args); + } + + if (env != null) { + log.debug("with Env:"); + for (int i = 0; i < env.length; i++) { + String[] nameValue = env[i].split("=", 2); + if (nameValue.length < 2) + throw new MojoFailureException(" Misformed env: '" + + env[i] + "'"); + log.debug(" '" + env[i] + "'"); + cmdLine.addEnvironment(nameValue[0], nameValue[1]); + } + } + + try { + Process process = cmdLine.execute(); + StreamGobbler errorGobbler = new StreamGobbler(process + .getErrorStream(), true, log); + StreamGobbler outputGobbler = new StreamGobbler(process + .getInputStream(), false, log); + + errorGobbler.start(); + outputGobbler.start(); + process.waitFor(); + return process.exitValue(); + } catch (Throwable e) { + throw new MojoExecutionException("Could not launch " + cmdLine, e); + } + } + + static class StreamGobbler extends Thread { + InputStream is; + boolean error; + Log log; + + StreamGobbler(InputStream is, boolean error, Log log) { + this.is = is; + this.error = error; + this.log = log; + } + + public void run() { + try { + BufferedReader reader = new BufferedReader( + new InputStreamReader(is)); + String line = null; + while ((line = reader.readLine()) != null) { + if (error) { + log.error(line); + } else { + log.debug(line); + } + } + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/main/java/org/apache/maven/plugin/nar/OS.java b/src/main/java/org/apache/maven/plugin/nar/OS.java new file mode 100644 index 0000000..838f803 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/OS.java @@ -0,0 +1,15 @@ +// Copyright FreeHEP, 2007. +package org.freehep.maven.nar; + +/** + * + * @author Mark Donszelmann + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/OS.java bf894e19f5aa 2007/07/07 15:33:36 duns $ + */ +public interface OS { + + public final String MACOSX = "MacOSX"; + public final String WINDOWS = "Windows"; + public final String LINUX = "Linux"; + public final String SUNOS = "SunOS"; +} diff --git a/src/main/java/org/apache/maven/plugin/nar/SysLib.java b/src/main/java/org/apache/maven/plugin/nar/SysLib.java new file mode 100644 index 0000000..8204bae --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/SysLib.java @@ -0,0 +1,47 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.types.LibraryTypeEnum; +import net.sf.antcontrib.cpptasks.types.SystemLibrarySet; + +import org.apache.maven.plugin.MojoFailureException; +import org.apache.tools.ant.Project; + +/** + * Keeps info on a system library + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/SysLib.java eda4d0bbde3d 2007/07/03 16:52:10 duns $ + */ +public class SysLib { + + /** + * Name of the system library + * + * @parameter expression="" + * @required + */ + private String name; + + /** + * Type of linking for this system library + * + * @parameter expression="" default-value="shared" + * @required + */ + private String type = Library.SHARED; + + public SystemLibrarySet getSysLibSet(Project antProject) throws MojoFailureException { + if (name == null) { + throw new MojoFailureException("NAR: Please specify <Name> as part of <SysLib>"); + } + SystemLibrarySet sysLibSet = new SystemLibrarySet(); + sysLibSet.setProject(antProject); + sysLibSet.setLibs(new CUtil.StringArrayBuilder(name)); + LibraryTypeEnum sysLibType = new LibraryTypeEnum(); + sysLibType.setValue(type); + sysLibSet.setType(sysLibType); + return sysLibSet; + } +} diff --git a/src/main/java/org/apache/maven/plugin/nar/Test.java b/src/main/java/org/apache/maven/plugin/nar/Test.java new file mode 100644 index 0000000..ac51491 --- /dev/null +++ b/src/main/java/org/apache/maven/plugin/nar/Test.java @@ -0,0 +1,68 @@ +// Copyright FreeHEP, 2005-2007. +package org.freehep.maven.nar; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.maven.plugin.MojoFailureException; + +/** + * Sets up a test to create + * + * @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a> + * @version $Id: plugin/src/main/java/org/freehep/maven/nar/Test.java c867ab546be1 2007/07/05 21:26:30 duns $ + */ +public class Test implements Executable { + + /** + * Name of the test to create + * + * @required + * @parameter expression="" + */ + protected String name = null; + + /** + * Type of linking used for this test + * Possible choices are: "shared" or "static". + * Defaults to "shared". + * + * @parameter expression="" + */ + protected String link = Library.SHARED; + + /** + * When true run this test. + * Defaults to true; + * + * @parameter expresssion="" + */ + protected boolean run=true; + + /** + * Arguments to be used for running this test. + * Defaults to empty list. This option is + * only used if run=true. + * + * @parameter expression="" + */ + protected List/*<String>*/ args = new ArrayList(); + + public String getName() throws MojoFailureException { + if (name == null) throw new MojoFailureException("NAR: Please specify <Name> as part of <Test>"); + return name; + } + + public String getLink() { + return link; + } + + public boolean shouldRun() { + return run; + } + + public List/*<String>*/ getArgs() { + return args; + } +} + |