We are using ANT as build and TestNG for execution.
if it would not been testNG then i know how to create JAR. in the below ANT i would have given MAIN class file but i dont know in case of TESTNG what should i provide in manifest
<target name="jar" depends="compile">
<jar destfile="${dist.dir}\ServerSpaceAlert.jar" basedir="${build.dir}">
<manifest>
<attribute name="Main-Class" value="test.MAIN" />
</manifest>
</jar>
</target>
Can somebody please help me.
Thanks
S
Related
<jar destfile="somefile" manifest="META-INF/MANIFEST.MF">
This script runs for multiple projects. Some of the projects have a manifest file, others don't. Build fails on a project that does not have a manifest file.
Is there a way to configure this jar task, so that ant uses project manifest file if it exists and generates a manifest file for a jarred project that doesn't have its own manifest?
Here's a sample I created. This has two jar tasks: jar and jar1. One uses the if check and the other the unless check. The ant target 'all' calls both, but only 1 should run. It checks if the manifest file exsts and if so uses that file, otherwise you can create a local in the jar1 task.
If you want to have only the 1 jar target, then you may need to use the Ant-Contrib tasks and use the tag. Here is a good link to review for this too.
<project name="StackOverflow" basedir="." default="all">
<property name="src.dir" value="${basedir}/src"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<target name="all" depends="compile,jar,jar1"/>
<target name="check-manifest">
<available file="META-INF/MANIFEST.MF" property="manifest.present"/>
</target>
<target name="jar" depends="check-manifest" if="manifest.present">
<echo>Using existing manifest.mf</echo>
<jar destfile="hello.jar" manifest="META-INF/MANIFEST"/>
</target>
<target name="jar1" depends="check-manifest" unless="manifest.present">
<echo>creating local manifest</echo>
<jar destfile="hello.jar">
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Permissions" value="all-permissions"/>
<attribute name="Codebase" value="*"/>
</manifest>
<fileset dir="${classes.dir}">
<include name="**/*.*"/>
</fileset>
</jar>
</target>
</project>
My company only uses Ant to build projects. However, Jenkins only suggests Maven as a build tool for plugin development.
How could I package my Jenkins plugin to a .hpi file using Ant and avoiding Maven at all costs?
Here is a way to build a Jenkins plugin using Ant. Let's make a script that builds a plugin skeleton which name is "awesome".
Default plugin arborescence
awesome-plugin/
-- awesome/
-- src/
-- pom.xml
Instructions
Add a lib/ folder which contains the following jars:
to be found in your Jenkins home directory Jenkins\war\WEB-INF\lib (note: you have to use the exact same versions that your current Jenkins use):
access-modifier-annotation-1.4.jar
bridge-method-annotation-1.4.jar
commons-io-1.4.jar
guava-11.0.1.jar
jenkins-core-1.513.jar
json-lib-2.4-jenkins-1.jar
remoting-2.23.jar
sezpoz-1.9.jar
stapler-1.207.jar
to be found on the web (you can choose the last version released):
servlet-api-2.4.jar
Replace the existing pom.xml with the following build.xml.
In the Ant script, you should adapt:
the project name, awesome here,
the plugin version,
the Jenkins version this plugin is made for,
the project group.id (main package), org.jenkinsci.plugins.awesome here.
New plugin arborescence
awesome-plugin/
-- awesome/
-- src/
-- lib/
-- you should have 10 jars here
-- build.xml
build.xml
<!-- Project dependent properties -->
<property name="project_name" value="awesome"/>
<property name="project_version" value="1.0"/>
<property name="jenkins_version" value="1.513"/> <!-- which version of Jenkins is this plugin built against? -->
<property name="project_groupid" value="org.jenkinsci.plugins.awesome"/>
<!-- Build properties -->
<property name="lib_dir" value="./lib"/>
<property name="bin_dir" value="./bin" />
<property name="target_dir" value="./target"/>
<property name="target_bin_dir" value="${target_dir}/${project_name}"/>
<property name="plugin_targetMetaInf_dir" value="${target_bin_dir}/META-INF"/>
<property name="plugin_targetWebInf_dir" value="${target_bin_dir}/WEB-INF"/>
<property name="plugin_targetWebInfBin_dir" value="${plugin_targetWebInf_dir}/classes"/>
<!-- Project paths -->
<path id="project.source.path">
<pathelement path="src/main/java" />
</path>
<path id="project.class.path">
<fileset dir="${lib_dir}" includes="*.jar"/>
</path>
<!-- Build flow -->
<target name="build">
<antcall target="clean" />
<antcall target="compile" />
<antcall target="createTreeDirectory" />
<antcall target="copyBin"/>
<condition property="has_file">
<and>
<available file="${target_dir}/${project_name}.hpi" type="file"/>
</and>
</condition>
<antcall target="createHpi"/>
<condition property="has_dir">
<and>
<available file="${target_bin_dir}" type="dir"/>
</and>
</condition>
<antcall target="cleanTargetDirectory" />
</target>
<!-- Cleans existing binaries -->
<target name="clean">
<delete includeEmptyDirs="true" quiet="true">
<fileset dir="${bin_dir}" />
</delete>
<mkdir dir="${bin_dir}"/>
</target>
<!-- Compiles JAVA code -->
<target name="compile">
<javac includeantruntime="false" destdir="${bin_dir}" debug="false" optimize="${optimize}" deprecation="${deprecation}" classpathref="project.class.path">
<src refid="project.source.path" />
</javac>
</target>
<!-- Creates necessary target folders -->
<target name="createTreeDirectory" >
<mkdir dir="${target_bin_dir}"/>
<mkdir dir="${plugin_targetMetaInf_dir}"/>
<mkdir dir="${plugin_targetWebInf_dir}"/>
<mkdir dir="${plugin_targetWebInfBin_dir}"/>
</target>
<!-- Moves new binaries to the plugin target -->
<target name="copyBin">
<copy todir="${plugin_targetWebInfBin_dir}" >
<fileset dir="${bin_dir}"/>
<fileset dir="src/main/resources"/>
</copy>
</target>
<!-- Cleans the target directory -->
<target name="cleanTargetDirectory" if="has_dir">
<delete dir="${target_bin_dir}"/>
</target>
<!-- Backup previous plugin -->
<target name="saveOldHpiFile" if="has_file">
<move file="${target_dir}/${project_name}.hpi" tofile="${target_dir}/${project_name}.save.hpi"/>
</target>
<!-- Archives the plugin -->
<target name="createHpi">
<antcall target="saveOldHpiFile"/>
<jar destfile="${target_dir}/${project_name}.hpi" basedir="${target_bin_dir}">
<manifest>
<attribute name="Manifest-Version" value="{project_version}"/>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Created-By" value="${user.name}"/>
<attribute name="Build-Jdk" value="${ant.java.version}"/>
<attribute name="Extension-Name" value="${project_name}"/>
<attribute name="Implementation-Title" value="${project_name}"/>
<attribute name="Implementation-Version" value="${version}"/>
<attribute name="Group-Id" value="${project_groupid}"/>
<attribute name="Short-Name" value="${project_name}"/>
<attribute name="Long-Name" value="${project_name}"/>
<attribute name="Plugin-Version" value="${project_version}"/>
<attribute name="Jenkins-Version" value="${jenkins_version}"/>
<attribute name="Hudson-Version" value="${jenkins_version}"/>
</manifest>
</jar>
</target>
To launch the build, cd towards the build.xml and type ant.
I know you stated "at all costs", but a compromise might be less effort, and still give super fast builds. A big reason for me to try to avoid maven is that the compile time is sloooowwwwww. That said, maven is quite good at creating the hpl file, and handling dependencies. The following targets are quite useful for helping to set up a super-fast non-maven build:
use 'mvn hpi:hpl' to generate the hpl file
use 'mvn dependency:copy-dependencies' to download all your dependencies, and put them into target/dependency, where it's easy to reference them from your ant script (you can add a symbolic link if necessary, from lib to target/dependency)
I'm interesting in building a "fat jar" in my Java project where Ivy resolves the dependencies. It seems wasteful to me to have to copy the referenced jar files from the ivy cache to the local project, so I'd like to avoid doing that. I found a solution that works, but wonder if there is a slightly simpler way. In the code below what I thought would be easiest is for the zipfileset line to work, but it does not - the jars are included in the built jar file, but they are not expanded. If instead I use the section it works properly, but seems like a bit of extra fuss. Is there a cleaner way of doing this?
<target depends="clean, build" name="jar">
<ivy:cachefileset setid="Ping.runclasspath" conf="default" />
<jar destfile="dist/Ping.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="Class-Path" value="."/>
</manifest>
<fileset dir="build"/>
<zipfileset refid="Ping.runclasspath"/> <--- this does NOT work
<restrict> <--- this DOES work
<name name="**/*.class"/>
<archives>
<zips>
<fileset refid="Ping.runclasspath"/>
</zips>
</archives>
</restrict>
</jar>
</target>
Have you experimented with zipgroupfileset? I don't know if it would actually work in your example, but it seems to have a similar purpose for existence.
I just had to do the same thing in one of my ant projects. Chris' suggestion of using zipgroupfileset works:
<target depends="clean, build" name="jar">
<ivy:cachefileset setid="Ping.runclasspath" conf="default" />
<jar destfile="dist/Ping.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
<attribute name="Class-Path" value="."/>
</manifest>
<fileset dir="build"/>
<zipgroupfileset refid="Ping.runclasspath"/>
</jar>
</target>
Here is my Ant script for generating jar package. I have bunch of jar packages for manifest Class-Path attribute, they are all in an specific folder.
I don't want to hard code it, how can I get them automatically?
<jar jarfile="${client_deploy_dir}/HelloWorld.jar"
basedir="${client_work_dir}/compiled">
<manifest>
<attribute name="Main-Class" value="HelloWorld.Main"/>
<attribute name="Class-Path" value="???"/>
</manifest>
</jar>
Thanks
You're on the right track, use manifestclasspath task. The jarfile attribute is used to create relative links to the jars contained in the fileset.
<manifestclasspath property="jar.classpath" jarfile="${client_work_dir}/HelloWorld.jar">
<classpath>
<fileset name="" dir="${client_work_dir}/lib" includes="*.jar"/>
</classpath>
</manifestclasspath>
<jar jarfile="${client_deploy_dir}/HelloWorld.jar" basedir="${client_work_dir}/compiled">
<manifest>
<attribute name="Main-Class" value="HelloWorld.Main"/>
<attribute name="Class-Path" value=""${jar.classpath}"/>
</manifest>
</jar>
Check out the ant pathconvert task. You can use this to expand an existing fileset into a list of files.
I have written an ANT script and finally am building the jar
here is the building of jar section
<jar jarfile="${destination}/#{name}.jar">
<fileset dir="${output}">
<include name="abc/xyz/#{name}/**"/>
</fileset>
<zipfileset dir="lib" prefix="lib/"/>
<manifest>
<attribute name="Main-Class" value="com.abc.xyz.HelloWorld"/>
<attribute name="Class-Path" value=".:lib/activation.jar:lib/antlr-2.7.6.jar:lib/asm-attrs.jar:lib/asm.jar:lib/cglib-2.1.3.jar:lib/commons-collections-2.1.1.jar:lib/commons-logging-1.1.jar:lib/dom4j-1.6.1.jar:lib/ehcache-1.2.3.jar:lib/ejb3-persistence.jar:lib/hibernate-annotations.jar:lib/hibernate-commons-annotations.jar:lib/hibernate-entitymanager.jar:lib/hibernate-tools.jar:lib/hibernate3.jar:lib/javassist.jar:lib/jdbc2_0-stdext.jar:lib/jta.jar:lib/mysql-connector-java-5.1.5-bin.jar"/>
</manifest>
</jar>
Now when I try to execute the package it executes, but whenever data is sent I get an error.
java.lang.NoClassDefFoundError: javax/persistence/NoResultException
But the persistence jar is there in the class-path, I've tried all the combinations for the class-path, but in vain.
But in another system I tried without create a jar like
set classpath=.;lib/activation.jar;lib/antlr-2.7.6.jar;lib/asm-attrs.jar;lib/asm.jar;lib/cglib-2.1.3.jar;lib/commons-collections-2.1.1.jar;lib/commons-logging-1.1.jar;lib/dom4j-1.6.1.jar;lib/ehcache-1.2.3.jar;lib/ejb3-persistence.jar;lib/hibernate-annotations.jar;lib/hibernate-commons-annotations.jar;lib/hibernate-entitymanager.jar;lib/hibernate-tools.jar;lib/hibernate3.jar;lib/javassist.jar;lib/jdbc2_0-stdext.jar;lib/jta.jar;lib/mysql-connector-java-5.1.5-bin.jar
java com.abc.xyz.HelloWorld
This works fine.
In Mac when I try like this:
java -cp .:lib/activation.jar:lib/antlr-2.7.6.jar:lib/asm-attrs.jar:lib/asm.jar:lib/cglib-2.1.3.jar:lib/commons-collections-2.1.1.jar:lib/commons-logging-1.1.jar:lib/dom4j-1.6.1.jar:lib/ehcache-1.2.3.jar:lib/ejb3-persistence.jar:lib/hibernate-annotations.jar:lib/hibernate-commons-annotations.jar:lib/hibernate-entitymanager.jar:lib/hibernate-tools.jar:lib/hibernate3.jar:lib/javassist.jar:lib/jdbc2_0-stdext.jar:lib/jta.jar:lib/mysql-connector-java-5.1.5-bin.jar com.abc.xyz.HelloWorld
Also it works fine :(, but the minute I create the jar it stops.
How can I resolve this issue?
First of all the "Main-Class" and "Class-Path" manifiest entries is only used for executeable jars. In other words when you invoke java as follows:
java -jar foo.jar
Invoking java using the -cp option means you're supplying your own classpath and note that you also have to provide the main class on the command line as well.
Secondly you need to replace the ":" characters with spaces:
<attribute name="Class-Path" value=". lib/activation.jar lib/antlr-2.7.6.jar lib/asm-attrs.jar lib/asm.jar lib/cglib-2.1.3.jar lib/commons-collections-2.1.1.jar lib/commons-logging-1.1.jar lib/dom4j-1.6.1.jar lib/ehcache-1.2.3.jar lib/ejb3-persistence.jar lib/hibernate-annotations.jar lib/hibernate-commons-annotations.jar lib/hibernate-entitymanager.jar lib/hibernate-tools.jar lib/hibernate3.jar lib/javassist.jar lib/jdbc2_0-stdext.jar lib/jta.jar lib/mysql-connector-java-5.1.5-bin.jar"/>
Finally I'd recommend using the manifestclasspath task to build your classpath string for you. It will correcly resolve any relative links between your jar and it's run-time dependencies.
<manifestclasspath property="mf.classpath" jarfile="${destination}/#{name}.jar">
<classpath>
<fileset dir="lib" includes="*.jar"/>
<classpath>
</manifestclasspath>
<jar jarfile="${destination}/#{name}.jar">
<fileset dir="${output}">
<include name="abc/xyz/#{name}/**"/>
</fileset>
<zipfileset dir="lib" prefix="lib/"/>
<manifest>
<attribute name="Main-Class" value="com.abc.xyz.HelloWorld"/>
<attribute name="Class-Path" value=". ${mf.classpath}"/>
</manifest>
</jar>
One final observation.... Why are you including the contents of the lib directory inside the jar? (The zipfileset tag in the jar command?)
This appears unnecessary, all you need to do is ensure that the run-time dependencies are present in a lib directory as specified in your Class-Path manifest entry.
The reason for it not works was there not in the class path, the explanation is given here:
Java-Jar-Ignores-Classpath-Workaround