summaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/maven/plugin
diff options
context:
space:
mode:
authorMark Donszelmann <Mark.Donszelmann@gmail.com>2009-10-01 14:33:24 +0200
committerMark Donszelmann <Mark.Donszelmann@gmail.com>2009-10-01 14:33:24 +0200
commit846700d44b67b22835b57a1c04f17043db8323a3 (patch)
treea253ecd4ada6f80dbcd08177035cfa71ade9b670 /src/main/java/org/apache/maven/plugin
parent0a8746644d70eb8b1cfb615c27155c19e09f46d3 (diff)
downloadmaven-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/org/apache/maven/plugin')
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/AOL.java49
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/AbstractCompileMojo.java208
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/AbstractDependencyMojo.java27
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/AbstractNarMojo.java129
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/AttachedNarArtifact.java66
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/C.java18
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Compiler.java496
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Cpp.java17
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Executable.java10
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Fortran.java18
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Java.java126
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Javah.java237
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Lib.java97
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Library.java117
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Linker.java348
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarArchiver.java12
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarArtifact.java26
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarArtifactHandler.java39
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarAssemblyMojo.java99
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarCompileMojo.java296
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarConstants.java14
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarDownloadMojo.java72
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarInfo.java169
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarIntegrationTestMojo.java987
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarJavahMojo.java24
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarLogger.java76
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarManager.java363
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarPackageMojo.java135
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarResourcesMojo.java162
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarSystemGenerate.java79
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarTestCompileMojo.java225
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarTestMojo.java148
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarUnArchiver.java12
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarUnpackMojo.java52
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/NarUtil.java417
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/OS.java15
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/SysLib.java47
-rw-r--r--src/main/java/org/apache/maven/plugin/nar/Test.java68
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 &lt;defines&gt;.
+ *
+ * @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 &lt;undefines&gt;.
+ *
+ * @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 &lt;options&gt;.
+ *
+ * @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 &lt;options&gt;.
+ *
+ * @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 &lt;libs&gt;.
+ * 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 &lt;sysLibs&gt;.
+ * 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: &lt;narDependencyLibOrder&gt;someGroup:myProduct, other.group:productB&lt;narDependencyLibOrder&gt;
+ * </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>**&#47;${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>**&#47;Test*.java **&#47;*Test.java **&#47;*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>**&#47;Abstract*Test.java **&#47;Abstract*TestCase.java **&#47;*$*</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;
+ }
+}
+