Ivy OutOfMemoryError during ivy:publish - java

I am having an issue with Ivy uploading large(ish) artifacts to our in-house artifact server (Artifactory 3.9.2). When we upload a 400MB file, we run out of Java heap space and it fails (thus failing our CI build). We keep nudging the upper limit up, but we're anticipating some significantly larger artifacts (~1GB in size) that is going to break our steady bumping in size.
We are using Ant 1.10, Ivy 2.4, OpenJSK 1.8.0.141, on a CentOS7 environment.
The issue has been documented with Ivy as IVY-1197 but it has not been fixed in a trunk build, so I want to put the described workaround:
The workaround is to always use ivy with commons-httpclient, commons-codec and commons-logging when the use case will involve uploading large files to sites requiring authentication
I want to add the commons-httpclient, commons-codec, and commons-logging to the Ivy classpath so that Ivy uses these during upload of the artifacts. Unfortunately, I am struggling to make this work. To be completely honest, I am a newcomer to the Java world, with classpaths being a foreign concept; I'm a C++ developer who has volunteered to fix this legacy part of our system.
We invoke our Ivy tasks through Ant. We pull in an ivysettings.xml file, whose relevant structure looks something like:
<ivysettings>
<classpath file="${build-utils.basedir}/ivy.lib/commons-httpclient-3.1.jar"/>
<classpath file="${build-utils.basedir}/ivy.lib/commons-codec-1.10.jar"/>
<classpath file="${build-utils.basedir}/ivy.lib/commons-logging-1.2.jar"/>
</ivysettings>
The ivysettings.xml is pulled in through a build-utils.xml file that is shared among our components:
<project name="build-utils" xmlns:ivy="antlib:org.apache.ivy.ant">
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant">
<classpath>
<fileset dir="${build-utils.basedir}/ant.lib">
<include name="ivy*.jar"/>
</fileset>
</classpath>
</taskdef>
<ivy:settings file="${build-utils.basedir}/ivysettings.xml"/>
<target name="convert-POM-to-Ivy" > <!-- description="Convert a POM file to an Ivy file"; additionally verifies that we've pulled in Ivy correctly -->
<ivy:convertpom pomFile="pom.xml" ivyFile="ivyFileOut.xml" />
</target>
</project>
We also have an ivy.xml for each of our components that is pretty straightforward:
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
<info organisation = "${groupId}"
module = "${artifactId}"
revision = "${version}}"/>
<configurations>
<include file="ivy-configurations.xml"/>
</configurations>
<!-- Some giant artifact -->
<artifact conf="${conf.el7}" type="tar.bz2" e:classifier="${conf.el7}"/>
<artifact type="pom"/>
<dependencies />
</ivy-module>
If I run the ant echoproperties target and grep for 'class.path' I get the following:
[echoproperties]
java.class.path=/usr/share/java/ant.jar\:/usr/share/java/ant-launcher.jar\:/usr/share/java/jaxp_parser_impl.jar\:/usr/share/java/xml-commons-apis.jar\:/usr/lib/jvm/java/lib/tools.jar\:/usr/share/ant/lib/ant-bootstrap.jar\:/usr/share/ant/lib/ant-launcher.jar\:/usr/share/ant/lib/ant.jar
[echoproperties]
java.class.path.ivy.instance=/usr/share/java/ant.jar\:/usr/share/java/ant-launcher.jar\:/usr/share/java/jaxp_parser_impl.jar\:/usr/share/java/xml-commons-apis.jar\:/usr/lib/jvm/java/lib/tools.jar\:/usr/share/ant/lib/ant-bootstrap.jar\:/usr/share/ant/lib/ant-launcher.jar\:/usr/share/ant/lib/ant.jar
With this setup, I still have issues with the upload, and I'm not sure if I can verify that I'm using the commons-httpclient.
Could someone provide some tips on how to get a jar into the Ivy classpath? Am I doing this wrong and I need to have it in the Ant classpath? If so, can someone point me in the right direction?

Related

ivy doesn't download jar from remote after local

I configured ivy to go first maven local repo then remote. But something is going wrong! (By the way, im working with snapshots)
If ivy cache doesn't exist, ivy first checks maven local repo and then remote to get required jars. Everything is fine.
If ivy cache exists, ivy just checks local repo! It doesn't check remote! I have 2 problem here:
If I change something in maven project and install it to local repo of maven, ivy still gets the jar from its cache, not in local repo of maven.
Even worse, it doesn't get any jar in remote if requsted jars in ivy cache.
ivysettings.xml
<ivysettings>
<settings defaultResolver="chain_resolver"/>
<credentials host="localhost"
realm="Sonatype Nexus Repository Manager"
username="username" passwd="password"/>
<property name="nexus.repo" value="url here"/>
<property name="nexus-public" value="http://${nexus.repo}:8081/nexus/content/groups/public"/>
<property name="m2-pattern" value="${user.home}/.m2/repository/[organisation]/[module]/[revision]/[module]-[revision](-[classifier]).[ext]"/>
<resolvers>
<chain name="chain_resolver">
<ibiblio name="nexus" m2compatible="true" root="${nexus-public}"/>
<filesystem name="local" m2compatible="true">
<artifact pattern="${m2-pattern}"/>
<ivy pattern="${m2-pattern}"/>
</filesystem>
</chain>
</resolvers>
</ivysettings>
Related ant tasks
<target name="ivy-download" unless="offline">
<mkdir dir="${ivy.dir}"/>
<get src="${repo_public}/org/apache/ivy/ivy/${ivy.ver}/ivy-${ivy.ver}.jar" dest="${ivy.jar}" usetimestamp="true"/>
</target>
<target name="ivy-install" depends="ivy-download">
<path id="ivy.lib.path">
<fileset file="${ivy.jar}"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
<ivy:settings file="ivysettings.xml" />
</target>
<target name="lib.get">
<mkdir dir="${lib.dir}"/>
<ivy:retrieve type="jar" conf="lib" pattern="${lib.dir}/[artifact]-[revision].[ext]"/>
</target>
<target name="ivy.lib.get" depends="ivy-install" if="${skipClean}">
<antcall target="lib.get" />
</target>
<target name="ivy.clean.lib.get" depends="ivy-install" unless="${skipClean}">
<ivy:cleancache/>
<antcall target="lib.get" />
</target>
How can I check
First, local repo and if there is a change, download from local repo
Then, remote and if there is a change, download from remote
And there is one more possible situation here which is, if there is a change in remote and local at the same time, what should I do?
Ivy has a local cache dedicated to that purpose. Improving performance by avoiding repeated download of the same artifact. Maven, on the other hand, uses its local repository as a cache (Ivy keeps these concepts separate).
The one operational problem with caches is that over time they become dirty, especially when sharing "integration" or "snapshot" builds.
For this reason I suggest you stop pointing ivy at the Maven local cache for the following reasons:
You're creating a strong dependency between two different build technologies.
You're caching a cache, rather than caching a repository.... It's a false economy, due to the risk of dirty caches.
My suggestion is simplify everything by introducing a Maven repository manager like Nexus, in order to both cache files from Maven Central and host artifacts shared between project builds.

approch for inter-project dependencies

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>

deleting jars from ivy resolved libraries

I have two jars that conflict in my libraries in the java build path. Both of them are resolved by ivy, so I see them inside an ivy.xml entry on the libraries tab. I can't delete anything inside the ivy.xml entry, eclipse only lets me delete the entire entry. Deleting the jar from the source folder is'nt viable either, since I don't have the access rights for that.
Could you give me some advice on how to solve this conflict?
Thanks for your time.
Use exclude in your ivy file, eg.:
<dependency org="log4j" name="log4j" rev="1.2.17" conf="default" >
<exclude module="javaee-api"/>
<exclude module="geronimo-jms_1.1_spec"/>
</dependency>
You can use following ant task to create dependency report:
<target name="report" >
<delete dir="report"/>
<mkdir dir="report" />
<ivy:resolve type="${ivy.resolve.types}"/>
<ivy:report todir="report" />
</target>

Automate ivy revision increase for all my projects using ant script

i own 20 ivy projects out of 50 other projects(owned by others), i use some versions of their binaries in my projects.
Issue is during release, i have to manually increase the version of my 20 ivy files, checkin the files and build the binaries. which is time consuming. though eclipse find and replace helps.
steps to automate using ant:
1) checkout the ivy files alone.
2) using scripts/logic to change the version for only my modules/my modules dependency with one another.
3) check in the files.
4) tag the branch for release.
Stuck at step 2 rest all are relatively easy.
Tried xml task, but facing challenges on searching as we dont know the exact index some times.
Appreciate your help.
Have you considered using the dynamic revision numbers in your ivy files?
<dependency org="myorg" name="myname1" revision="latest.release"/>
<dependency org="myorg" name="myname2" revision="latest.integration"/>
Ivy will cleverly resolve these dependencies in the ivy.xml file that is published to ivy repositories.
Use ivy to generate buildnumber
The buildnumber is a very clever task that generates the next number in a sequence, based on the versions you've already been published.
Controlling the build order
Another ivy multi-module tip is to use buildlist task to control the order in which your modules are built. It works based on the inter-dependencies declared in the ivy files of each sub-module. This ensures that the latest.release and latest.integration revisions will find the expected revision.
Resolving the dynamic revisions
As I've said this is normally done automatically, but sometimes you'll need to actually see the real versions used, for example when generating a Maven POM file (when publishing to a Maven repo).
The following examples use the ivy deliver and makepom tasks to create a Maven POM with the dynamic revisions expanded.
<target name="generate-pom">
<ivy:deliver deliverpattern="${build.dir}/ivy.xml" pubrevision="${publish.revision}" status="${publish.status}"/>
<ivy:makepom ivyfile="${build.dir}/ivy.xml" pomfile="${build.dir}/${ivy.module}.pom"/>
</target>
<target name="publish" depends="build,generate-pom">
<ivy:publish resolver="${publish.resolver}" pubrevision="${publish.revision}" overwrite="true" publishivy="false" >
<artifacts pattern="${build.dir}/[artifact](-[classifier]).[ext]"/>
</ivy:publish>
</target>
If you always want to use the latest release, have you thought about using version ranges in dependencies? There will be no more need to edit the files for a new release. It would look like the following for spring core:
<dependency org="org.springframework" name="spring-core" rev="[2.5,4.0[" conf="optional->default"/>
Found the following workable solution myself, though tried other options like parsing the ivy.xml through IVY java etc.
<target name="autoincrementivy" depends="prompt-user.password">
<exec executable="svn" failonerror="${svn.failonerror}">
<arg value="--non-interactive"/>
<arg value="--trust-server-cert"/>
<arg value="--username"/>
<arg value="${svn.user}"/>
<arg value="--password"/>
<arg value="${svn.password}"/>
<arg value="checkout"/>
<arg value="--depth"/>
**<arg value="immediates"/>**
<arg value="${svn.repository}/#{module.name}/trunk"/>
<arg value="${temp.checkout.dir}/#{module.name}"/>
</exec>
<move file="${temp.checkout.dir}/ivy.xml" tofile="${temp.checkout.dir}/ivy_src.xml"/>
<ant target="changeVersion" antfile="../deploy.xml" >
<property name="dest.file" value="${temp.checkout.dir}/ivy.xml"/>
<property name="src.file" value="${temp.checkout.dir}/ivy_src.xml"/>
<property name="target.version" value="${tag.version}"/>
</ant>
<!-- cehckin the file-->
</target>
Above task to checkout the file to a temporary folder with .svn folder so that cehckin will work correctly.
<target name="changeVersion">
<xmltask source="${src.file}" dest="${dest.file}" preserveType="true" >
<replace path="/ivy-module/info/#revision" withText="${target.version}" />
<replace path="/ivy-module/dependencies/dependency[#name='my-common']/#rev" withText="${target.version}" />
<replace path="/ivy-module/dependencies/dependency[#name='my-gui-common']/#rev" withText="${target.version}" />
</xmltask>
<fixcrlf file="${src.file}" eol="cr" />
</target>
The above target to parse and change the version.

Beanshell in Ant yielding, "Unable to create javax script engine for beanshell"

Greeting, I'm trying to put some Beanshell script in my Ant build.xml file. I've followed the Ant manual as well as I can but I keep getting "Unable to create javax script engine for beanshell" when I run Ant. Here is the test target I wrote mostly from examples in the Ant manual:
<target name="test-target">
<script language="beanshell" setbeans="true">
<classpath>
<fileset dir="c:\TEMP" includes="*.jar" />
</classpath>
System.out.println("Hello world");
</script>
</target>
My beanshell "bsh-2.0b4.jar" file is on the script task's classpath the way the manual recommended. Hope I have the right file. I'm working in c:\TEMP right now.
I've been googling and trying for a while now. Any ideas would be greatly appreciated. Thanks.
First, you need jsr-engines.zip from here:
https://scripting.dev.java.net/servlets/ProjectDocumentList
Inside, you'll find jsr223/beanshell/build/bsh-engine.jar. Some searching implied that you need to download bsh-2.05b.jar. I found it here:
http://beanshell.org/bsh-2.0b5.jar
The more easily findable bsh-2.0b4.jar also seemed to work, but it printed a message that implied it was experimental.
Currently (2012) you need only 1 jar to fire the script task for BeanShell:
bsh-2.0b5.jar
Previously I also thought of the following, as mentioned by Ant Manual, Library Dependencies chapter:
bsf-2.4.0.jar
commons-logging-api-1.1.jar
But it looks like bsf is not needed for bsh, at least in my environment.
Once the jar is given to ant, the script task runs smoothly. There are 2 possible scenarios for getting the jars and making them available to ant.
Manual download way
Download the jars above. I provided the links from maven repository. Once you have all the jars downloaded, make them available to ant. There are
at least 3 ways to do it:
Put it in java library path
Put it in ant library directory
Give the correct classpath to script task.
I find the last method the best, because it is most easily ported between
different systems. The ant file for the script task could look as follows:
<project default="t1" >
<property name="bsh.path"
location="/mnt/q/jarek/lang/java/ant/stackoverflow/bsh-2.0b5.jar" />
<target name="t1">
<script language="beanshell" classpath="${bsh.path}">
javax.swing.JOptionPane.showMessageDialog(null, "Hello, Script!");
</script>
</target>
</project>
Automatic download method, employing Ivy
The manual method is not perfect when you want to distribute your build script. Then you would like a way to make sure the jars are present in the destination system. For distributing builds there's no better tool than ivy. Ivy will download the jars and put them in classpath for you. The problem is that there appears another dependency, which is ivy itself. But providing ivy.jar is quite easy and that is the last dependency we need to supply explicitly.
One may ask why to provide ivy.jar, while we could simply download bsh.jar in the same way. The answer is flexibility. When you have the ivy.jar, you get any jar you wish with a single step being adding it to the ivy.xml file. And there is an agreed universal location for the ivy.jar file, while for other file we would have to think of a suitable directory.
Below comes the full example that downloads ivy and then all the necessary dependencies. Ivy download script is based on Installation chapter of Ivy reference.
Then a simple ivy.xml file is needed, which is given after the sample build.xml.
Original auto-download ivy script has a disadvantage of always checking the ivy url, even if ivy.jar is already in the expected location. This may be overriden by specifying -Doffline=true. I prefer to add another target to the build file and to do the http check only if we don't already have the ivy.jar. This is the way the script here works. To observe what ivy actually downloaded, set IVY_HOME environment variable to a directory of your choice. It will be created and filled with ivy stuff.
build.xml:
<project default="t1"
xmlns:ivy="antlib:org.apache.ivy.ant" >
<property name="ivy.install.version" value="2.2.0" />
<property environment="env" />
<condition property="ivy.home" value="${env.IVY_HOME}">
<isset property="env.IVY_HOME" />
</condition>
<property name="ivy.home" value="${user.home}/.ant" />
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
<target name="check-ivy">
<condition property="ivy.present">
<available file="${ivy.jar.file}" type="file" />
</condition>
</target>
<target name="download-ivy" unless="ivy.present">
<mkdir dir="${ivy.jar.dir}"/>
<!-- download Ivy from web site so that it can be used even without any special installation -->
<get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
</target>
<target name="init-ivy" depends="check-ivy, download-ivy">
<!-- try to load ivy here from ivy home, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>
<target name="ivy-libs" depends="init-ivy" >
<ivy:cachepath pathid="path.from.ivy" log="download-only" />
</target>
<target name="t1" depends="ivy-libs" >
<script language="beanshell" classpathref="path.from.ivy">
javax.swing.JOptionPane.showMessageDialog(null, "Hello, Script!");
</script>
</target>
</project>
ivy.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="example.com" module="testing-script-task" />
<dependencies>
<dependency org="org.beanshell" name="bsh" rev="2.0b5" />
<!-- <dependency org="bsf" name="bsf" rev="2.4.0" /> -->
</dependencies>
</ivy-module>
The Ant plug-in "org.apache.ant_1.7.0.v200803061910" have all the jar files needed
Don't use beanshell language. Use javascript instead, as it runs on jdk6 without any additional jars. Rebse told me that.
Javascript is also allowed to use java classes, for example java.lang.System.out.println()

Categories