Today I wanted to perform this task, and I run across some issues in the way. So I present here my problem and the solution I found. Perhaps somebody knows a simpler solution!
The problem was this: I was trying to build a distribution package of a Java project which is built with Maven2. In a previous step, several zip files all containing a file named manifest.xml in the root were generated, and I wanted to modify this XML file in all this ZIP files. This is a scheme:
package-file-1.zip
|- contents(DIR)
\- manifest.xml
package-file-2.zip
|- contents(DIR)
\- manifest.xml
This example modifies the zip files in ${zip.sourcedir} replacing the string & with & in the file manifest.xml of all this zip files and places the modified zip files in the directory target.
For that, it uses the maven-antrun-plugin including the for and var tasks from the antcontrib tasks(http://ant-contrib.sourceforge.net). This permits to unzip the contents of every zip file into a separate directory. Note also the use of the task basename to extract the name of the zip files out of their path.
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>copy-and-repair-zips</id>
<phase>initialize</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="maven.plugin.classpath"/>
<for param="filepath">
<path>
<fileset dir="${zip.sourcedir}" includes="**/*.zip"/>
</path>
<sequential>
<var name="for.filename" unset="true" />
<basename property="for.filename" file="#{filepath}" />
<unzip src="#{filepath}" dest="target/repair-temp/${for.filename}" encoding="UTF8" />
<replace file="target/repair-temp/${for.filename}/manifest.xml" token="&" value="&" encoding="UTF8" />
<zip basedir="target/repair-temp/${for.filename}" destfile="target/${for.filename}" encoding="UTF8" />
</sequential>
</for>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>1.0b3</version>
<exclusions>
<exclusion>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
In order to write this solution, I got the needed knowledge from this URLs:
Modify a JAR(or ZIP) file using Ant: How do I modify a file in a jar file using ANT?
Unzip multiple files into separate directories: http://grokbase.com/t/ant.apache.org/user/2004/01/re-how-to-unzip-multiple-file-into-separate-directories/122a5ezxhh6eolf5enkrdfgryika
Use ant-contrib in Maven2: http://docs.codehaus.org/display/MAVENUSER/Antrun+Plugin
But be careful to use net/sf/antcontrib/antlib.xml instead of net/sf/antcontrib/antcontrib.properties to be able to use the for task
Use the ant-contrib var task: http://www.jguru.com/forums/view.jsp?EID=1374074
Edit
After posting the question, I was able to find a couple of questions related, that could help if one is having problems implementing a similar thing:
maven3 - maven-antrun-plugin - "failed to create task or type if"
Using antcontrib <if> task via maven-antrun-plugin
Related
I have a Maven build and i'd like to build some property based on files found in the resources.
Concretely, I'd like to build a ${builtinLocales} variable at the "process-resources" phase based the resources found. I can then incorporate it in some application property file.
E.g. if 2 files "labels_en.properties" and "labels_de.properties" are found, that variable should return "en;de" or "labels_en;labels_de".
The ultimate goal is to present to the users the available languages without having to, at run time, parse the full jar for seek after "^labels_(\w+)\.properties$" files.
Anyway to do this ?
Based on the answers to Using maven replacer plugin to list files in a folder and Exporting Maven properties from Ant code, I came up with this solution:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>list-locales</id>
<phase>generate-resources</phase>
<configuration>
<target>
<fileset id="my-fileset" dir="src/main/resources">
<filename regex="[^/]+_.+.properties"/>
</fileset>
<pathconvert targetos="unix" pathsep=";"
property="project.locales" refid="my-fileset">
<map from="${basedir}\src\main\resources\" to="" />
<regexpmapper from="[^/]+?_(.+).properties" to="\1"/>
</pathconvert>
</target>
<exportAntProperties>true</exportAntProperties>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>1.0b3</version>
<exclusions>
<exclusion>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</plugin>
The solution relies on :
Building a Ant property "project.locales" based on the files found
Exposing this Ant property to Maven with <exportAntProperties>true</exportAntProperties>
Using the the Maven property ${project.locales} in any file where required.
I'm new with Maven, I just finished to read the Sonatype guide and I'm very satisfied by the functions that maven makes available. I created an application distribution (.zip) package and I would like to know if there is a manner to use maven as an installer.
I don't mean the installation that maven does into the local repository, what I mean is explained by the following example:
I've a folder with a jar file, an .sql script, a /lib and obviously a pom.xml file.
I would like that maven installs this project for me when I execute the "mvn" command.
So maven should:
- Copy the jar file in the ${TOMCAT_HOME}\webapps directory.
- Execute the sql script on the postgresql database
- Copy the \lib directory in c:\myLibs
- etc etc
During this process it should also make some checks (example TOMCAT_HOME is set on the system? Postgres is turned on? etc.) and ask to the user some parameter (example "The installation will reset the database do you want to continue?" or "Please insert the database password: ".
Is there a maven plugin that helps to do this? If not is there an application alike maven specialized to create "installer" ? Is it a standard, widespread application?
Thanks a lot for your help!
Try:
mvn deploy.
Add to your pom
<distributionManagement>
<repository>
<id>sonatype.internal</id>
<name>Internal Release Repository</name>
<url>http://sonatypeAddress:sonatypePort/context</url>
</repository>
</distributionManagement>
Plugins section:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<configuration>
<tag>${build.tag}</tag>
<username>${scm.username}</username>
<password>${scm.password}</password>
</configuration>
</plugin>
antrun plugin - and make what you want.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<dependencies>
...
</dependencies>
<executions>
<execution>
<id>install</id>
<phase>install</phase>
<configuration>
<target>
<delete dir="mylocalization" />
<copy file="target/out/my.jar" tofile="mylocalication" />
<copy todir="mylocalization/doc">
<fileset dir="target/doc" />
</copy>
<copy todir="mylocalization/somethingMore">
<fileset dir="target/more">
<include name="a.txt" />
<include name="b*.txt" />
</fileset>
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
See also maven-wagon
I'm working on a plugin for Talend Open Studio; the component architecture of that platform needs that all external JARs are declared in a component-descriptor XML file in a form like:
<IMPORT MODULE="commons-collections-3.2.1.jar" NAME="commons-collections-3.2.1"
REQUIRED="true"/>
I use the Maven dependency plugins to manage all these external JARs
Is there a way to get all the dependency names in a list or something? This way can I be able to build the required strings (using an antcontrib task, perhaps), fill a ${parameter} and finally add it to XML file using maven-replacer-plugin?
The simplest solution is to use the maven-dependency-plugin via the buld-classpath goal. This goal can be given supplemental parameters to put the result into a file like:
mvn dependency:build-classpath -Dmdep.outputFile=classpath.out
Ok, I partly resolved this way that should works with some limitations:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<dependencies>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>1.0b3</version>
<exclusions>
<exclusion>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>1.6.5</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<id>copy-resources</id>
<configuration>
<exportAntProperties>true</exportAntProperties>
<tasks>
<!-- add the ant tasks from ant-contrib -->
<taskdef resource="net/sf/antcontrib/antlib.xml" classpathref="maven.plugin.classpath"/>
<var name="import.set" value=""/>
<for param="file">
<path>
<fileset dir="${project.build.directory}" includes="*.jar"/>
</path>
<sequential>
<var name="basename" unset="true"/>
<basename file="#{file}" property="basename"/>
<var name="filenames" value="${basename}"/>
<var name="import.clause" value='<IMPORT MODULE="${filenames}" NAME="${filenames}" REQUIRED="true"/>'/>
<var name="import.set" value="${import.clause}${line.separator}${import.set}" />
</sequential>
</for>
<property name="import.jar" value="${import.set}"/>
<echo>${import.jar}</echo>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
Still some problems: even if exportAntProperties is set to true, the property ${import.jar} is still not available outside ant taska in other maven goals, while if i switch to maven-antrun-plugin 1.7 version, a "Error executing ant tasks: org.apache.tools.ant.launch.Locator.fromJarURI(Ljava/lang/String;)Ljava/lang/String;" exception is thrown. Still no clues...
Let's say I have a project that uses a dependency that can be found in the Maven repository. However, lets also say that the jar file that will be downloaded is NOT in a format that is suitable for my project (e.g. if my maven project is an Android project and the jar has been compiled in a way the dex tool does not like). What I want to do instead is to downloaded the source version of that dependency. Once I add java-source, however, the classes are not accessible anymore from my own source code. I would like that maven downloads the source jar and compiles the java files inside it and places the compiled class files in the classpath. Is that possible?
My only alternative is to create a new project containing that library myself, but that's cumbersome.
You could do the following:
Use maven dependency plugin's unpack goal and place the contents of the dependency into a folder
Use build-helper-maven-plugin's add-source goal to add this folder as a source folder
Here is some code snippet...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>unpack</id>
<phase>process-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>my.group</groupId>
<artifactId>my.artifact</artifactId>
<version>my.artifact.version</version>
<classifier>sources</classifier>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/my.artifact</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/my.artifact.source</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
Downloading the source packages using Maven is easy:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
<classifier>sources</classifier>
</dependency>
How to configure Maven to expand this dependency and then compile it's contents is beyond me....
Have you considered an ANT solution? The ivy plug-in provides it with Maven-like abilities and the groovy plug-in can be used to script your special build logic:
build.xml
Ivy uses "configurations" (similar to Maven scopes) to group dependencies.
In this example the "sources" configuration holds the downloaded source packages. These are placed into a referenced fileset, which can be processed sequentially by the groovy task.
Each downloaded source jar is unzipped into the "build/src" directory:
<project name="demo" default="unzip-sources" xmlns:ivy="antlib:org.apache.ivy.ant">
<property name="build.dir" location="build"/>
<property name="src.dir" location="${build.dir}/src"/>
<target name="resolve">
<ivy:resolve/>
<ivy:cachepath pathid="build.path" conf="build"/>
<ivy:cachefileset setid="sourcezips" conf="sources"/>
</target>
<target name="unzip-sources" depends="resolve">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
project.references.sourcezips.each {
ant.unzip(src: it, dest: properties["src.dir"])
}
</groovy>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
</project>
ivy.xml
Each source package dependency uses the "sources" configuration. This maps directly to the "sources" scope of the Maven module.
<ivy-module version="2.0">
<info organisation="org.myspotontheweb" module="demo"/>
<configurations>
<conf name="build" description="ANT tasks"/>
<conf name="sources" description="Source packages"/>
</configurations>
<dependencies>
<!-- Build dependencies -->
<dependency org="org.codehaus.groovy" name="groovy-all" rev="1.8.2" conf="build->default"/>
<!-- Source dependencies -->
<dependency org="log4j" name="log4j" rev="1.2.16" conf="sources"/>
<dependency org="commons-lang" name="commons-lang" rev="2.6" conf="sources"/>
</dependencies>
</ivy-module>
I'm currently working on a fairly large project that has been migrated from Ant to Maven. There are no problems with the actual build process (it compiles and packages the source code fine).
The problem is that I also have a lot of targets that generate additional resources for the project (compile LessCSS, generate & upload documentation, generate tld files for custom tags and functions etc.). I am not sure how I should handle these tasks. Let's take the target that builds CSS&JS as an example (the others are more or less similar, but not connected). It looks like this (simplified):
<target name="build.css_js">
<concat destfile="${webapp.dir}/scripts/main.js">
<fileset dir="${webapp.dir}/scripts/src" includes="*.js"/>
</concat>
<!-- build css files from less sources -->
<taskdef name="lesscss" classname="com.asual.lesscss.LessEngineTask" classpathref="libraries" />
<lesscss input="${webapp.dir}/syles/src/input.less" output="${webapp.dir}/styles/output.css" />
</target>
In the pom.xml I have the following plugin set up:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<configuration>
<tasks>
<echo message="Hello World from pom.xml"/>
<ant target="build.css_js"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
The dependencies I'm using are no longer in our SVN repository (since they are managed by Maven), so I switched the libraries variable to point to the Maven repo:
<property name="lib.dir" location="${env.HOMEPATH}/.m2/repository" />
This is not good, as that path may be valid only on my machine. I don't know any other way to reference the libraries from the Maven repository and I need them to run the ant targets.
Is my approach ok or is there a better way of doing things?
How do I get over the library problem?
Some resources are needed when packaging the project but some are not. Is there a lifecycle phase that is out of scope for compile/package? I found the site lifecycle which I think fits my needs.
Ideally, I should give up on the ant build file altogether, but I'm not sure it's worth the effort of making the scripts run as maven plugins (I currently have no idea how to do that). What do you think about this?
I'm new to Maven so any suggestions are appreciated.
Generally embedding antrun calls is not ideal, but if you've not found a suitable plugin to do what you need then I wouldn't worry about it. If the processing is fairly simple it is actually quite easy to embed it in a Maven plugin yourself, see this example for help getting started.
If you are going with antrun, and the dependency jars have already been installed to your Maven repository, you can configure the antrun plugin to use those jars in its execution by adding them as dependencies of the plugin configuration. This means the dependencies will be resolved and available for use, but not be visible to your project (useful to help avoid accidental inclusion). To then access them in a portable way you can use:
<property name="lib.dir" location="${settings.localRepository}" />
Alternatively you can use some of the other properties available to expose the Maven classpaths to the antrun plugin, for example ${maven.compile.classpath} See the antrun documentation for more details.
If you have multiple discrete executions for ant, you can configure them individually in the antrun plugin and specify a suitable id for each one. The example below shows two executions, both bound to the process-resources phase. Of course you need to supply some actual goals.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>build-css</id>
<phase>generate-resource</phase>
<configuration>
<target>
...
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>build-js</id>
<phase>generate-resource</phase>
<configuration>
<target>
...
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>some.group.id</groupId>
<artifactId>artifactId</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>another.group.id</groupId>
<artifactId>anotherId</artifactId>
<version>1.0.1</version>
</dependency>
</dependencies>