如何告诉Ivy将下载的jar包放在自定义目录中?

20

我对Ivy完全不熟悉,一直在简单地尝试它,用于获取中央Maven存储库中常用的库,例如GuavaGson,这些库可用

<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>

默认情况下,Ivy在Windows上将其文件存储在%USERPROFILE%\.ivy2\cache\中;在类Unix系统上,则会下载到$HOME/.ivy2/目录下。

我想这是一个相当基本的问题:如何告诉Ivy下载二进制和源,并将二进制jar放入一个(任意的)目录和源jar放入另一个目录

例如,我希望Ivy将所有下载的二进制jar文件放在[project_home]/WebContent/WEB-INF/lib目录中。

请注意,我是通过以下方式使用Ant来使用Ivy,而不是使用IDE插件。

<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>
3个回答

19

另一个SO答案描述了如何使用配置来保持依赖项组的分离。然而,这个问题可能需要将依赖项声明多次以适应不同的ivy配置。

请尝试以下操作:

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>

注意: 已更新以添加清除 Ivy 缓存的目标。

构建过程如下,以确保获取最新的构件:

$ ant clean-all resolve

结果

$ 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

证明源代码包含Java文件的证据:

$ 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.

搞定了,谢谢!有点遗憾需要一些冗余(为二进制和源文件分别使用<dependency>),但没关系。顺便说一下,我在ivy.xml中省略了conf="binaries->default"和build.xml中的conf="binaries",因为没有它们也能正常工作。 - Jonik
不,等等,它对源代码不起作用 :/ 我以为它实际上下载了源代码的jar包,但事实上它下载了二进制的jar包两次,并将其放在源目录下。有什么想法吗? - Jonik
我的示例可以工作。为了控制每个配置文件的内容,您需要指定本地和远程配置之间的显式映射(在Maven中称为“范围”)。使用conf="binaries"不会起作用。Maven不支持名为“binaries”的范围。 - Mark O'Connor
澄清一下,使用上述配置无法获取源代码jar包。试试看:查看例如gson-sources.jar文件的内容,看看它是否实际包含.java文件(而不是.class文件)。如果您知道如何使其工作,请告诉我。 - Jonik
再次测试通过(答案已扩展)。我正在使用ANT 1.8.2和ivy 2.2.0。 - Mark O'Connor

8

~/.ivy2是ivy缓存

您需要设置ivy retrieve的模式。这将定义依赖项下载的位置。

<ivy:retrieve pattern="${project_home}/WebContent/WEB-INF/lib/[artifact].[ext]" conf="jars"/>

可能还需要第二次检索源代码:

<ivy:retrieve pattern="${project_home}/sources/[artifact].[ext]" conf="sources"/>

这种方法也可行,将源代码和JAR文件的依赖放在不同的目录中:
<ivy:retrieve pattern="${project_home}/[conf]/[artifact].[ext]" conf="sources, jars"/>

这取决于您在存储库中指定源/ jar 的方式。

另外一件事: taskdef 必须在使用任务之前定义。

并且您应将解析器定义为m2compatible:

<ibiblio name="maven2" m2compatible="true"/>

谢谢!我正在尝试这种设置,但现在出现了错误:“报告文件'~/.ivy2/cache/com.company-foobar-jars.xml'不存在”。如果我需要在ivy缓存目录下手动创建这样的文件,那么这似乎很奇怪...我的Ivy配置还有什么遗漏吗? - Jonik
@Jonik 很难说,你在检索之前执行了 ivy:resolve/ 吗? - oers
不行;我尝试添加ivy:resolve/,但仍然得到相同的错误。从错误信息来看,似乎我不能在ivy:retrieve调用中简单地添加conf="jars"而不在某处定义“jars”配置:asked configuration not found in com.company#foobar;working@jonik: jars。但是如何做到这一点呢? - Jonik
@jonik,jars和sources只是举例子,你需要知道你的依赖项可用哪些conf值。查看依赖项的ivy.xml文件。所有在publications下面的内容都有一个conf,可以使用它。如果你的依赖项在maven存储库中,请查看这里:https://dev59.com/rGw05IYBdhLWcg3wqzis - oers
是的,我首先尝试使用默认Maven仓库中可用的常见库来使用Ivy;问题展示了我所拥有的一切。对于二进制JAR文件,我只需完全删除conf="jars"即可使其正常工作;现在JAR文件会放到WEB-INF/lib中。但我仍然不知道如何为源代码做到这一点。看着那个问题的被接受答案,我认为“sources”可能是一个有效的conf名称,但事实并非如此。显然,我需要在ivy.xml中声明/映射confs;我正在查看这篇博客文章来学习如何操作。 - Jonik

1
我遇到了类似的问题,但情况略微棘手,提供的解决方案并不适用。我有一个主要的ivy.xml文件,它没有定义任何配置,因此继承了默认配置,即使你不注意也会创建(请参见doc)。在所有依赖项上应用新制作的“main”配置只会破坏构建。我别无选择,只能在另一个文件中定义一个新模块,例如ivy_extra.xml,并在新目标中加载它,就这么简单!
示例文件:
<!-- ivy_extra.xml -->
<ivy-module version="2.0">
    <info organisation="com.myorg" module="mymodule"/>
    <configurations>
        <conf name="download" visibility="private" />
    </configurations>
    <dependencies>
        <dependency org="com.google.guava" name="guava" rev="10.0.1" conf="download->default"/>
    </dependencies>
</ivy-module>

在您的 build.xml 文件中加载如下:

<target name="download-guava" description="Retrieve guava">
    <echo>Retrieving guava</echo>
    <ivy:resolve file="ivy_agent.xml"/>
    <ivy:retrieve conf="download" type="jar" pattern="guava/[artifact]-[revision].jar"/>
</target>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接