How to tell Ivy to put downloaded jars in a custom directory?

Jonik picture Jonik · Dec 29, 2011 · Viewed 20.7k times · Source

I'm a total newbie with Ivy, and have been trying it out very simply, for fetching commonly used libraries such as Guava and Gson that are available in the central Maven repository:

<ivy-module version="2.0">
    <info organisation="com.company" module="foobar"/>    
    <dependencies>
        <dependency org="com.google.guava" name="guava" rev="10.0.1"/>
        <dependency org="com.google.code.gson" name="gson" rev="2.0"/>
    </dependencies>    
</ivy-module>

On Windows, by default, Ivy stores its files in %USERPROFILE%\.ivy2\cache\; on Unix-y systems, they are downloaded under $HOME/.ivy2/.

I suppose this is pretty basic question: how to tell Ivy to download both binaries and sources, and to put the binary jars in one (arbitrary) directory and source jars in another directory?

For example, I'd like Ivy to put all downloaded binary jars in [project_home]/WebContent/WEB-INF/lib.

Note that I'm using Ivy via Ant, along the following lines, not an IDE plugin.

<project xmlns:ivy="antlib:org.apache.ivy.ant" name="ivy" default="resolve" > 
    <target name="resolve" description="retrieve dependencies with ivy">
        <ivy:retrieve/>
    </target>

    <path id="ivy.lib.path">
        <fileset dir="tools/buildlibs" includes="*.jar"/>
    </path>
    <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>        
</project>

Answer

Mark O&#39;Connor picture Mark O'Connor · Jan 3, 2012

Another SO answer describes how configurations are used to keep groups of dependencies separate. This problem however might require the dependencies to be declared more than once to fit into different ivy configurations.

Try the following:

ivy.xml

<ivy-module version="2.0">
    <info organisation="com.company" module="foobar"/>    
    <configurations>
        <conf name="sources"  description="Source jars"/>
        <conf name="binaries" description="binary jars"/>
    </configurations>
    <dependencies>
        <dependency org="com.google.guava" name="guava" rev="10.0.1" conf="sources->sources"/>
        <dependency org="com.google.code.gson" name="gson" rev="2.0" conf="sources->sources"/>

        <dependency org="com.google.guava" name="guava" rev="10.0.1" conf="binaries->default"/>
        <dependency org="com.google.code.gson" name="gson" rev="2.0" conf="binaries->default"/>
    </dependencies>    
</ivy-module>

build.xml

<project xmlns:ivy="antlib:org.apache.ivy.ant" name="hello-ivy" default="resolve">

    <target name="resolve" description="retrieve dependencies with ivy">
        <ivy:retrieve conf="sources" pattern="lib/[conf]/[artifact](-[classifier]).[ext]"/>
        <ivy:retrieve conf="binaries" pattern="lib/[conf]/[artifact](-[classifier]).[ext]"/>
    </target>

    <target name="clean" description="Remove build directories">
        <delete dir="lib"/>
    </target>

    <target name="clean-all" depends="clean" description="clean ivy cache">
        <ivy:cleancache />
    </target>

</project>

Note: Updated to add target which purges ivy cache.

Build is run as follows, to ensure artifacts are freshly downloaded:

$ ant clean-all resolve

Result

$ find . -type f
./build.xml
./ivy.xml
./lib/sources/gson-sources.jar
./lib/sources/guava-sources.jar
./lib/binaries/gson.jar
./lib/binaries/jsr305.jar
./lib/binaries/guava.jar

Proof that the source artifact contains java files:

$ unzip -t ./lib/sources/gson-sources.jar
Archive:  ./lib/sources/gson-sources.jar
    testing: META-INF/                OK
    testing: META-INF/MANIFEST.MF     OK
    testing: com/                     OK
    testing: com/google/              OK
    testing: com/google/gson/         OK
    testing: com/google/gson/annotations/   OK
    testing: com/google/gson/internal/   OK
    testing: com/google/gson/internal/bind/   OK
    testing: com/google/gson/reflect/   OK
    testing: com/google/gson/stream/   OK
    testing: com/google/gson/annotations/Expose.java   OK
    testing: com/google/gson/annotations/package-info.java   OK
    testing: com/google/gson/annotations/SerializedName.java   OK
    testing: com/google/gson/annotations/Since.java   OK
    testing: com/google/gson/annotations/Until.java   OK
    testing: com/google/gson/AnonymousAndLocalClassExclusionStrategy.java   OK
    testing: com/google/gson/Cache.java   OK
    testing: com/google/gson/CamelCaseSeparatorNamingPolicy.java   OK
    testing: com/google/gson/CompositionFieldNamingPolicy.java   OK
    testing: com/google/gson/DefaultTypeAdapters.java   OK
    testing: com/google/gson/DisjunctionExclusionStrategy.java   OK
    testing: com/google/gson/ExclusionStrategy.java   OK
    testing: com/google/gson/ExposeAnnotationDeserializationExclusionStrategy.java   OK
    testing: com/google/gson/ExposeAnnotationSerializationExclusionStrategy.java   OK
    testing: com/google/gson/FieldAttributes.java   OK
    testing: com/google/gson/FieldNamingPolicy.java   OK
    testing: com/google/gson/FieldNamingStrategy.java   OK
    testing: com/google/gson/FieldNamingStrategy2.java   OK
    testing: com/google/gson/FieldNamingStrategy2Adapter.java   OK
    testing: com/google/gson/Gson.java   OK
    testing: com/google/gson/GsonBuilder.java   OK
    testing: com/google/gson/GsonToMiniGsonTypeAdapterFactory.java   OK
    testing: com/google/gson/InnerClassExclusionStrategy.java   OK
    testing: com/google/gson/InstanceCreator.java   OK
    testing: com/google/gson/internal/$Gson$Preconditions.java   OK
    testing: com/google/gson/internal/$Gson$Types.java   OK
    testing: com/google/gson/internal/bind/ArrayTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/BigDecimalTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/BigIntegerTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/CollectionTypeAdapterFactory.java   OK
    testing: com/google/gson/internal/bind/DateTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/ExcludedTypeAdapterFactory.java   OK
    testing: com/google/gson/internal/bind/JsonElementReader.java   OK
    testing: com/google/gson/internal/bind/JsonElementWriter.java   OK
    testing: com/google/gson/internal/bind/MapTypeAdapterFactory.java   OK
    testing: com/google/gson/internal/bind/MiniGson.java   OK
    testing: com/google/gson/internal/bind/ObjectTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/Reflection.java   OK
    testing: com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java   OK
    testing: com/google/gson/internal/bind/SqlDateTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/StringToValueMapTypeAdapterFactory.java   OK
    testing: com/google/gson/internal/bind/TimeTypeAdapter.java   OK
    testing: com/google/gson/internal/bind/TypeAdapter.java   OK
    testing: com/google/gson/internal/bind/TypeAdapterRuntimeTypeWrapper.java   OK
    testing: com/google/gson/internal/bind/TypeAdapters.java   OK
    testing: com/google/gson/internal/ConstructorConstructor.java   OK
    testing: com/google/gson/internal/LazilyParsedNumber.java   OK
    testing: com/google/gson/internal/ObjectConstructor.java   OK
    testing: com/google/gson/internal/package-info.java   OK
    testing: com/google/gson/internal/Pair.java   OK
    testing: com/google/gson/internal/ParameterizedTypeHandlerMap.java   OK
    testing: com/google/gson/internal/Primitives.java   OK
    testing: com/google/gson/internal/Streams.java   OK
    testing: com/google/gson/internal/UnsafeAllocator.java   OK
    testing: com/google/gson/JavaFieldNamingPolicy.java   OK
    testing: com/google/gson/JsonArray.java   OK
    testing: com/google/gson/JsonDeserializationContext.java   OK
    testing: com/google/gson/JsonDeserializer.java   OK
    testing: com/google/gson/JsonDeserializerExceptionWrapper.java   OK
    testing: com/google/gson/JsonElement.java   OK
    testing: com/google/gson/JsonElementVisitor.java   OK
    testing: com/google/gson/JsonIOException.java   OK
    testing: com/google/gson/JsonNull.java   OK
    testing: com/google/gson/JsonObject.java   OK
    testing: com/google/gson/JsonParseException.java   OK
    testing: com/google/gson/JsonParser.java   OK
    testing: com/google/gson/JsonPrimitive.java   OK
    testing: com/google/gson/JsonSerializationContext.java   OK
    testing: com/google/gson/JsonSerializer.java   OK
    testing: com/google/gson/JsonStreamParser.java   OK
    testing: com/google/gson/JsonSyntaxException.java   OK
    testing: com/google/gson/LongSerializationPolicy.java   OK
    testing: com/google/gson/LowerCamelCaseSeparatorNamingPolicy.java   OK
    testing: com/google/gson/LowerCaseNamingPolicy.java   OK
    testing: com/google/gson/LruCache.java   OK
    testing: com/google/gson/ModifierBasedExclusionStrategy.java   OK
    testing: com/google/gson/ModifyFirstLetterNamingPolicy.java   OK
    testing: com/google/gson/package-info.java   OK
    testing: com/google/gson/RecursiveFieldNamingPolicy.java   OK
    testing: com/google/gson/reflect/package-info.java   OK
    testing: com/google/gson/reflect/TypeToken.java   OK
    testing: com/google/gson/SerializedNameAnnotationInterceptingNamingPolicy.java   OK
    testing: com/google/gson/stream/JsonReader.java   OK
    testing: com/google/gson/stream/JsonScope.java   OK
    testing: com/google/gson/stream/JsonToken.java   OK
    testing: com/google/gson/stream/JsonWriter.java   OK
    testing: com/google/gson/stream/MalformedJsonException.java   OK
    testing: com/google/gson/stream/StringPool.java   OK
    testing: com/google/gson/SyntheticFieldExclusionStrategy.java   OK
    testing: com/google/gson/UpperCamelCaseSeparatorNamingPolicy.java   OK
    testing: com/google/gson/UpperCaseNamingPolicy.java   OK
    testing: com/google/gson/VersionConstants.java   OK
    testing: com/google/gson/VersionExclusionStrategy.java   OK
No errors detected in compressed data of ./lib/sources/gson-sources.jar.