I am trying to integrate Apache Ivy in a Netbeans web app project.
My build.xml file follows the netbeans tutorial:
http://wiki.netbeans.org/FaqIvy
Specifically:
<target name="-ivy-retrieve">
<ivy:retrieve/> <!-- Load dependencies to the project -->
<pathconvert property="ivy.classpath.computed" dirsep="/" pathsep=":">
<path>
<fileset dir="lib" includes="*.jar"/>
</path>
<map from="${basedir}${file.separator}" to=""/>
</pathconvert>
<propertyfile file="nbproject/project.properties">
<entry operation="=" key="ivy.classpath" value="${ivy.classpath.computed}"/>
</propertyfile>
</target>
<target name="-pre-compile" depends="-ivy-retrieve"/>
<target name="-pre-compile-single" depends="-ivy-retrieve"/>
<target name="-post-clean">
<delete dir="lib"/>
</target>
Strangely, this updates ivy.classpath in the nbprojects.project.properties file but I can't seem to get the build's WEB-INF/lib folder to get populated with the .jar's that are listed as dependencies.
Strangely, I had this working the other day and was able to populate the build's WEB-INF/lib folder and now when I remove the dependency, the same jar files are included in the build (rather than removing them).
Any suggestions on how to change the build.xml file? Or anything else that will get Ivy successfully integrated into my build process (Ivy is detected: I see "resolution report" and "retrieving" in the output while building).
Some things I've tried:
I played around with different options in the above linked tutorial (tried including:
<property name="ivy.lib.dir" value="web/WEB-INF/lib/"/> in the -ivy-retrieve task or adding the <ivy:resolve/> task before <ivy:retrieve/>)
The ivy:retrieve task has a sync property which removes not longer relevant dependencies.
Also, doing a clean and build helps.
Related
I'm trying to bundle my .jar to a MacOSX app bundle, using app bundler.
I'm following this tutorial.
It says to add a lib folder to the high-level project directory, but I don't know what that means. I've been looking everywhere for it, and I cannot find out what it is. That's my only problem I have, anyone know?
EDIT:
Here is my build.xml file:
<project name="Rage Mage" basedir=".">
<taskdef name="ragemage"
classname="com.oracle.appbundler.AppBundlerTask"
classpath="lib/appbundler-1.0.jar" />
<target name="bundle-RageMage">
<delete dir="appBundle" failonerror="false"/>
<mkdir dir="appBundle"/>
<bundleapp outputdirectory="bundle"
name="Rage Mage"
displayname="Rage Mage"
icon="res/icon.icns"
identifier="ragemage.src.Window"
mainclassname="ragemage.src.Window">
<classpath file="dist/ragemage_1.1.1.jar" />
</bundleapp>
</target>
Thanks!
Okay, so, after having a little play around, this is what I understand...
Download Java Application Bundler and place it in the lib directory of your project. You will need to create this directory...
Create a new Ant script into your project directory, call it what ever you like...Also, take the time to read through the AppBundler Task Docs
The ant script should be based on the following skeleton...
<project name="ButtonDemo" default="bundle-buttonDemo" basedir=".">
<taskdef name="bundleapp"
classname="com.oracle.appbundler.AppBundlerTask"
classpath="lib/appbundler-1.0.jar" />
<!-- See the lib reference here, this is why you need to use the lib directory! -->
<target name="bundle-buttonDemo">
<delete dir="appBundle" failonerror="false"/>
<mkdir dir="appBundle"/>
<bundleapp outputdirectory="appBundle"
name="ButtonDemo"
displayname="Button Demo"
identifier="components.ButtonDemo"
mainclassname="components.ButtonDemo">
<!-- The following is important and should point to your build -->
<classpath file="dist/ButtonDemo.jar" />
<!-- You can have multiple instance of classpath if you 3rd party or
dependent jars in different locations -->
</bundleapp>
</target>
</project>
Build your project
Run the ant script, using (something like) ant -f {You App Bundler script}
The app bundle, in this case ButtonDemo.app will be created in appBundle directory. If you can, browse the contents of the ButtonDemo.app/Contents/Java and make sure all your required Jar files are there...
Happy bundling!
Updated based on updated build.xml file
1- There is no default target specified by the project tag. Think of this like your "main class" or "main" method, without, ant has no idea what you want to run...
<project name="Rage Mage" basedir="." default="bundle-RageMage">
2- The name of the taskdef is significant and you use it in the any script to identify what ant should do when it hits your tag reference...
So based on your example, you either need to change the name of the taskdef from ragemage to bundleapp or change the bundleapp tag to ragemage...
Either change this...
<taskdef name="bundleapp"
classname="com.oracle.appbundler.AppBundlerTask"
classpath="lib/appbundler-1.0.jar" />
or this (in target bundle-RageMage)
<ragemage outputdirectory="bundle"
name="Rage Mage"
displayname="Rage Mage"
icon="res/icon.icns"
identifier="ragemage.src.Window"
mainclassname="ragemage.src.Window">
<classpath file="dist/ragemage_1.1.1.jar" />
</ragemage>
Personally, I'd leave it as bundleapp, but that's me...
3- The delete, mkdir and outputdirectory attribute of bundleapp are related...
<delete dir="appBundle" failonerror="false"/>
<mkdir dir="appBundle"/>
<bundleapp outputdirectory="bundle"...
Either, make them all appBundle or bundle, what every you want...
4- You main class is unlikely to be ragemage.src.Window and is probably going to be Window
I have a console-based build system that's using Ant and Ivy and would like to avoid using Maven. I fetch my project's external dependencies using Ivy. My question is how best to handle my internal project dependencies. I.e. I build a number of library files (JARs) on which my modules are based and which unlikely to be used in another context. So these internal project dependencies are simply captured by build.xml files directly identifying the location of the needed JARs via relative paths (since everything's under the same source tree in the repository). E.g. I have Ant "code" like this:
<path id = "compile.classpath">
<fileset dir="${internal-project-dependency-a.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${internal-project-dependency-b.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${internal-project-dependency-c.dir}">
<include name ="*.jar"/>
</fileset>
</path>
My question is: is the above approach acceptable (from a best-practice point of view) or should I instead package and publish even my internal project dependencies in some lightweight "local-only" Ivy repository (if there's such a thing)? The way I've setup my system anyone with Ivy and Ant can checkout my sources from github and build everything from the console without needing to configure any other kind of Ivy repository information and I'd like to keep that property.
Ivy supports different kinds or repositories, described in the documentation.
local
shared
public
Without customization these are located under your "~/.ivy2" directory. So, I would recommend configuring each builds to publish to your local repository and simply reference dependencies as normal. All you need to do is ensure that on a fresh machine the build order is correct, so that the local repo is populated in the correct order (See the buildlist task).
Using the local repo is not very different from referencing the jars in known relative locations. It does have the benefit of making each project decoupled from the other.
Example
├── build.xml
└── ivy.xml
Project publishes 3 files to the local repository:
$ find ~/.ivy2/local -type f
/home/mark/.ivy2/local/myorg/hello/1.0/ivys/ivy.xml.sha1
/home/mark/.ivy2/local/myorg/hello/1.0/ivys/ivy.xml
/home/mark/.ivy2/local/myorg/hello/1.0/ivys/ivy.xml.md5
/home/mark/.ivy2/local/myorg/hello/1.0/docs/English.txt.md5
/home/mark/.ivy2/local/myorg/hello/1.0/docs/Spanish.txt.sha1
/home/mark/.ivy2/local/myorg/hello/1.0/docs/English.txt.sha1
/home/mark/.ivy2/local/myorg/hello/1.0/docs/Irish.txt.sha1
/home/mark/.ivy2/local/myorg/hello/1.0/docs/Spanish.txt.md5
/home/mark/.ivy2/local/myorg/hello/1.0/docs/English.txt
/home/mark/.ivy2/local/myorg/hello/1.0/docs/Spanish.txt
/home/mark/.ivy2/local/myorg/hello/1.0/docs/Irish.txt.md5
/home/mark/.ivy2/local/myorg/hello/1.0/docs/Irish.txt
build.xml
<project name="demo" default="publish" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="init">
<ivy:resolve/>
</target>
<target name="build" depends="init">
<mkdir dir="build"/>
<echo file="build/English.txt">Hello world</echo>
<echo file="build/Irish.txt">Dia dhuit</echo>
<echo file="build/Spanish.txt">Hola mundo</echo>
</target>
<target name="publish" depends="clean,build">
<ivy:publish pubrevision="1.0" status="release" resolver="local" >
<artifacts pattern="build/[artifact].[ext]"/>
</ivy:publish>
</target>
<target name="clean" description="Cleanup build files">
<delete dir="build"/>
</target>
</project>
ivy.xml
<ivy-module version="2.0">
<info organisation="myorg" module="hello"/>
<publications>
<artifact name="English" ext="txt" type="doc"/>
<artifact name="Irish" ext="txt" type="doc"/>
<artifact name="Spanish" ext="txt" type="doc"/>
</publications>
</ivy-module>
I'm trying to write an Ant build that does not require me adding Ant-plugins to Ant's lib directory, or /home/myuser/.ant/lib, or in my Eclipse instance's ant home, etc; namely because I will eventually be building my project on a hosted Jenkins server where I do not have access to the system's Ant installation.
I'm calling this a "self-bootstrapping" build, because I use Ivy to pull down my Ant plugins at build time, and hopefully, with some proper configuration, make their tasks available to Ant dynamically.
The jist of my build (using ant-contrib plugin as an example:
<?xml version="1.0" encoding="utf-8" ?>
<project name="myapp" default="audit" basedir="."
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:antcontrib="antlib:net.sf.antcontrib">
<!-- Build path. -->
<path id="build.path">
<fileset dir="${lib.buildtime.dir}" includes="**/*.jar"/>
</path>
<target name="bootstrap">
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="build.path"/>
</target>
<target name="resolve" depends="bootstrap">
<ivy:settings url="${ivy.settings.home}"/>
<ivy:cleancache/>
<ivy:resolve file="${ivy.xml}"/>
<ivy:retrieve pattern="${gen.lib.main.dir}/[artifact]-[revision].[ext]" conf="main"/>
<ivy:retrieve pattern="${gen.lib.test.dir}/[artifact]-[revision].[ext]" conf="test"/>
<ivy:retrieve pattern="${gen.lib.buildtime.dir}/[artifact]-[revision].[ext]" conf="buildtime"/>
<ivy:report todir="${gen.staging.dir}" />
<ivy:cachepath pathid="build.path" conf="buildtime"/>
</target>
<target name="taskdefs" depends="resolve">
<taskdef resource="/net/sf/antcontrib/antlib.xml"
uri="antlib:net.sf.antcontrib" classpathref="build.path"/>
<property name="fizz" value="buzz" />
<antcontrib:if>
<antcontrib:equals arg1="${fizz}" arg2="buzz" />
<antcontrib:then>
<echo message="Fizz is buzz!" />
</antcontrib:then>
<antcontrib:else>
<echo message="Fizz is not buzz!" />
</antcontrib:else>
</antcontrib:if>
</target>
</project>
When I run the taskdefs target, instead of seeing an echoed "Fizz is buzz!" message in my Ant output, I get the following error:
BUILD FAILED
/home/myuser/eclipse/workspace/myapp/build.xml:169: Problem: failed to create task or type antlib:net.sf.antcontrib:if
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
No types or tasks have been defined in this namespace yet
This appears to be an antlib declaration.
Action: Check that the implementing library exists in one of:
-/home/myuser/eclipse/plugins/org.apache.ant_1.8.3.v201301120609/lib
-/home/myuser/.ant/lib
-a directory added on the command line with the -lib argument
Is what I am trying to do (avoid having to do 1 of the 3 recommended things above) impossible? If so, why? If not, what is wrong with my setup here? Thanks in advance!
I normally create a single "boostrap" target and use this to install ivy into the "$HOME/.ant/lib" directory. See:
Ivy fails to resolve a dependency, unable to find cause
The following is a more complete example that does what you're trying to do:
How to include ant-contrib.jar dynamically in Ant
In conclusion, it's a shame ivy is not packaged by default with ANT. If you discover your hosted service prevents you from copying files into the home directory, then perhaps the simplest thing to do is ship a copy of the ivy jar alongside your source (and enable it using a taskdef)
Update
Use the following taskdef for ant-contrib:
<taskdef uri="antlib:net.sf.antcontrib" classpathref="build.path"/>
The homepage needs update. At some stage in the recent past the library was repackaged as an antlib.
I am having a little trouble with my first ever ant build in eclipse, here is my build.xml build file.
<project name="Rutherford" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<property name="libs" value="libs"/>
<path id="classpath">
<fileset dir="${libs}" includes="**/*.jar"/>
</path>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}" classpathref="classpath">
<compilerarg line="-encoding utf-8"/>
</javac>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/MyProject-${DSTAMP}.jar" basedir="${build}">
<manifest>
<attribute name="Main-Class" value="nat.rutherford.DesktopStarter"/>
</manifest>
</jar>
</target>
<target name="run">
<java jar="${dist}/MyProject-${DSTAMP}.jar" fork="true"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
It compiles ok with no warnings or errors, but when I try to run the .jar it says 'Could not find the main class: nat.rutherford.DesktopStarter. Program will now exit' =(
I have read a ton of pages on the matter but so far nothing conclusive.
I was able to compile it using Eclipse -> File -> Export ->Java -> Runnable Jar File. But I use some UTF-8 encoded .txt files that it seems not to be able to deal with that way and I need them! ie I have greek characters that should read...dσ/dΩ... but currently read... dÃ/d©... which isn't going to work ^^
So basically I need to make my Ant build work, baring in mind that it needs to be able to handle my UTF-8 encoded .txt files too.
The problem is in your task dist when you create your jar. If your compilation is right and there is no problem when you package your jar. Things that are wrong:
<mkdir dir="${dist}/lib"/> -> this don't have mean, you don't use it never
second you are not including your libraries in your jar, then when you try to execute your jar it doesn't work that why you are seeing the error message Could not find the main class: nat.rutherford.DesktopStarter. Program will now exit You could see that your libraries aren't within your jar using Winzip or similar. I suppose that you are seeing your problem when you try to execute the jar directly using windows or similar. A good way to see what is happening, seeing the problem printed in the console is executing your jar in the next way: java -jar MyProject-20120102.jar
See: How to include your libraries in you jar?
And if you want to know more about jar packaging using ant try this.
Another thing that you need to modify the Class-path attribute in your manifest to include the libraries within your ${libs} folder.
It looks like you've added a manifest to your executable JAR that spells out nat.rutherford.DesktopStarter as your main class.
I'd recommend that you open the JAR and verify that the manifest.mf appears and does indeed say what your Ant build.xml does.
I'd also verify that your DesktopStarted.class appears in a folder path nat.rutherford. If it doesn't, the JVM won't find it.
I'm using Apache Ant 1.8 to deploy a web application into a local Tomcat server, and the build.xml file (below) produces the desired effect when I run 'ant deploy' at the command line.
My question is, I noticed that the .war file gets placed where I expect it to (deploy.dir is defined in my home directory's build.properties file), but it also unexpectedly unpacked the .war and extracted the context itself into that same directory. Where in the below build.xml file is that configured?
<target name='init'>
<property file='${user.home}/build.properties'/>
<property name='app.name' value='${ant.project.name}'/>
<property name='src.dir' location='src'/>
<property name='lib.dir' location='lib'/>
<property name='build.dir' location='build'/>
<property name='classes.dir' location='${build.dir}/classes'/>
<property name='dist.dir' location='${build.dir}/dist'/>
</target>
<target name='initdirs' depends='init'>
<mkdir dir='${classes.dir}'/>
<mkdir dir='${dist.dir}'/>
</target>
<target name='compile' depends='initdirs'>
<javac srcdir='${src.dir}/java' destdir='${classes.dir}'>
<!--
<classpath>
<fileset dir='${lib.dir}/development' includes='javaee.jar'/>
<fileset dir='${lib.dir}/production' includes='jr.jar'/>
</classpath>
-->
</javac>
</target>
<target name='war' depends='compile'>
<war destFile='${dist.dir}/${app.name}.war' webxml='${src.dir}/web/WEB-INF/web.xml'>
<classes dir='${classes.dir}'/>
<!--
<zipfileset dir='${lib.dir}/production' includes='jr.jar' prefix='WEB-INF/lib' />
-->
<fileset dir='${src.dir}/web' excludes='WEB-INF/web.xml' />
</war>
</target>
<target name='build' depends='war' description='compile and create the war' />
<target name='clean' depends='init' description='Use for a clean build'>
<delete dir='${build.dir}' />
</target>
<target name='ffbuild' depends='clean, build' description='clean and create the war'/>
<target name='deploy' depends='initdirs' description='copy the war file to the app server'>
<delete verbose='true' dir='${deploy.dir}/${app.name}'/>
<fail unless='deploy.dir' message='build.properties must exist in your home directory and define deploy.dir' />
<copy todir='${deploy.dir}' file='${dist.dir}/${app.name}.war'/>
</target>
Tomcat has an autodeploy folder in which any war file that you place will be automatically unpacked and deployed. Your ant file is simply copying the war file into this directory by calling a special URL in the tomcat-manager web application (which is prepackaged into the tomcat).
From this point on everything is handled by the tomcat core automatically, just if you copied the war file into the webapps directory manually.
You can have ant do a lot more with some specific ant tasks for tomcat. Especially if the Tomcat server is not on the local machine. See this link for details.
You have autodeploy turned on in your Tomcat installation. This link gives a detailed overview of autodeploy, but in a nutshell, Tomcat scans certain directories for updated web.xml and war files. If it finds a war file it deploys it automatically.
A better way to deploy (especially if you'll ever need to deploy to a remote machine) is to use the Ant tasks that come with Tomcat. This page shows how to set up your build file so you can deploy and undeploy from Ant. The page is old but the information is still good. Here's a snippet of a build.xml I use to deploy to Tomcat:
<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask">
<classpath>
<path location="${build-jars}/catalina-ant.jar" />
</classpath>
</taskdef>
<target name="buildAndDeploy" depends="buildWar">
<deploy url="${tomcat.manager.url}"
username="${tomcat.manager.username}"
password="${tomcat.manager.password}"
path="/${target.name}"
update="true"
war="file:${basedir}/deploy/${target.name}.war" />
</target>
You can find catalina-ant.jar in Tomcat's lib directory.
I've had very good luck with Tomcat's Ant tasks for deployment. Have a look at the Executing Manager Commands With Ant documentation for information. If you decide to go that route, you should be able to get it working in short order.
Probably, you're first copying all your files in your dest dir an then making war file, you should instead copy your files to some temp directory, create war file, copy it to dest dir, remove temp directory.