为什么ivy会把我本地解析的jar放在libs目录下的子目录下

Why does ivy put my locally resolved jar in a sub directory within the libs directory

我对 ivy 没有那么多经验,也不确定如何解决这个问题,这可能是我自己不了解 ivy 造成的。

所以我在我的 ivysettings.xml 中有这个来使用本地文件系统 repo

<ivysettings>
   <settings defaultResolver="central" />
   <resolvers>
      <ibiblio name="central" m2compatible="true"/>
      <filesystem name='local'>
        <artifact pattern='/home/tester/JAVA/tester-libs/'/>
      </filesystem>
   </resolvers>
   <modules>
      <module organisation="myorg" resolver="local"/>
   </modules>
</ivysettings>

JarL.java 存在于 /home/tester/JAVA/tester-libs/

我的依赖项在ivy.xml中设置为

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="1.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="http://www.jayasoft.org/misc/ivy/samples/ivy.xsd"
>
    <info organisation="org.naps" module="naps"/>
    <dependencies>
        <dependency org="commons-configuration" name="commons-configuration" rev="1.10"/>
        <dependency org="myorg" name="Jarl" rev="NA" changing="true"/>
    </dependencies>
</ivy-module>

这解决了依赖关系,但是在构建过程中,所有其他 jar(如 commons-configuration)都放在 lib/ 中,我的 jar 放在 lib/JarL 子目录中。

我希望 JarL 像其他依赖项一样放在 lib/ 中,但不知道该怎么做。我从网上找到的其他答案中破解了这些脚本。

Ivy 对我来说太深入了。我不想花几个月的时间来学习另一种工具。我只想要简单的懒惰开发,让我专注于手头的问题而不是开发工具。

更新:

目前我不得不在 build.xml 中的打包步骤中添加以下两行来解决这个问题,但这是一个愚蠢的修复。

<move file="lib/JarL-NA.jar/JarL.jar" todir="lib"/>
<delete dir="lib/JarL-NA.jar"/>

更新: 根据马克的要求添加 build.xml

<?xml version="1.0" encoding="UTF-8"?><!-- You may freely edit this file. See commented blocks below for --><!-- some examples of how to customize the build. --><!-- (If you delete it and reopen the project it will be recreated.) --><!-- By default, only the Clean and Build commands use this build script. --><project name="Naps" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
    <description>Builds, tests, and runs the project Naps.</description>
    <import file="nbproject/build-impl.xml"/>
    <!--

    There exist several targets which are by default empty and which can be 
    used for execution of your tasks. These targets are usually executed 
    before and after some main targets. Those of them relevant for JavaFX project are: 

      -pre-init:                 called before initialization of project properties
      -post-init:                called after initialization of project properties
      -pre-compile:              called before javac compilation
      -post-compile:             called after javac compilation
      -pre-compile-test:         called before javac compilation of JUnit tests
      -post-compile-test:        called after javac compilation of JUnit tests
      -pre-jfx-jar:              called before FX SDK specific <fx:jar> task
      -post-jfx-jar:             called after FX SDK specific <fx:jar> task
      -pre-jfx-deploy:           called before FX SDK specific <fx:deploy> task
      -post-jfx-deploy:          called after FX SDK specific <fx:deploy> task
      -pre-jfx-native:           called just after -pre-jfx-deploy if <fx:deploy> runs in native packaging mode
      -post-jfx-native:          called just after -post-jfx-deploy if <fx:deploy> runs in native packaging mode
      -post-clean:               called after cleaning build products

    (Targets beginning with '-' are not intended to be called on their own.)

    Example of inserting a HTML postprocessor after javaFX SDK deployment:

        <target name="-post-jfx-deploy">
            <basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
            <property name="jfx.deployment.html" location="${jfx.deployment.dir}${file.separator}${jfx.deployment.base}.html"/>
            <custompostprocess>
                <fileset dir="${jfx.deployment.html}"/>
            </custompostprocess>
        </target>

    Example of calling an Ant task from JavaFX SDK. Note that access to JavaFX SDK Ant tasks must be
    initialized; to ensure this is done add the dependence on -check-jfx-sdk-version target:

        <target name="-post-jfx-jar" depends="-check-jfx-sdk-version">
            <echo message="Calling jar task from JavaFX SDK"/>
            <fx:jar ...>
                ...
            </fx:jar>
        </target>

    For more details about JavaFX SDK Ant tasks go to
    http://docs.oracle.com/javafx/2/deployment/jfxpub-deployment.htm

    For list of available properties check the files
    nbproject/build-impl.xml and nbproject/jfx-impl.xml.

    -->
    <target name="-check-for-ivy">
        <available property="have.ivy" resource="fr/jayasoft/ivy/ant/antlib.xml"/>
    </target>
    <target name="-ivy-define" depends="-check-for-ivy" unless="have.ivy">
        <taskdef resource="fr/jayasoft/ivy/ant/antlib.xml" uri="antlib:fr.jayasoft.ivy.ant">
            <classpath>
                <fileset dir="${ivy.home}">
                    <include name="ivy*.jar"/>
                    <include name="lib/*.jar"/>
                </fileset>
            </classpath>
        </taskdef>
    </target>
    <target name="-ivy-retrieve" depends="-ivy-define" xmlns:ivy="antlib:fr.jayasoft.ivy.ant">
        <ivy:resolve/> <!-- Tell Ivy to resolve dependencies -->
        <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>

    <!-- fix ivy task -->
    <target name="-pre-jfx-jar">
        <move file="lib/JarL-NA.jar/JarL.jar" todir="lib"/>
        <delete dir="lib/JarL-NA.jar"/>
    </target>
</project>

这是它加载的 nb 属性文件

#Thu, 02 Jul 2015 05:24:03 +0100
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.splash=
application.title=Naps
application.vendor=Tester
auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
compile.on.save=true
compile.on.save.unsupported.javafx=true
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=${run.classpath}
debug.test.classpath=${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/Naps.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
includes=**
# Non-JavaFX jar file creation is deactivated in JavaFX 2.0+ projects
jar.archive.disabled=true
jar.compress=false
#
# Tester - replaced classpath with ivy
javac.classpath=${ivy.classpath}\:${javafx.classpath.extension}
# javac.classpath=\
#    ${javafx.classpath.extension}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=${javac.classpath}
javac.source=1.8
javac.target=1.8
javac.test.classpath=${javac.classpath}\:${build.classes.dir}
javac.test.processorpath=${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
javafx.application.implementation.version=1.0
javafx.binarycss=false
javafx.classpath.extension=${java.home}/lib/javaws.jar\:${java.home}/lib/deploy.jar\:${java.home}/lib/plugin.jar
javafx.deploy.adddesktopshortcut=false
javafx.deploy.addstartmenushortcut=false
javafx.deploy.allowoffline=true
# If true, application update mode is set to 'background', if false, update mode is set to 'eager'
javafx.deploy.backgroundupdate=false
javafx.deploy.disable.proxy=false
javafx.deploy.embedJNLP=true
javafx.deploy.icon=
javafx.deploy.icon.native=
javafx.deploy.includeDT=true
javafx.deploy.installpermanently=false
javafx.deploy.permissionselevated=false
javafx.deploy.splash=
# Set true to prevent creation of temporary copy of deployment artifacts before each run (disables concurrent runs)
javafx.disable.concurrent.runs=false
# Set true to enable multiple concurrent runs of the same WebStart or Run-in-Browser project
javafx.enable.concurrent.external.runs=false
# This is a JavaFX project
javafx.enabled=true
javafx.fallback.class=com.javafx.main.NoJavaFXFallback
# Main class for JavaFX
javafx.main.class=naps.Main
javafx.preloader.class=
# This project does not use Preloader
javafx.preloader.enabled=false
javafx.preloader.jar.filename=
javafx.preloader.jar.path=
javafx.preloader.project.path=
javafx.preloader.type=none
# Set true for GlassFish only. Rebases manifest classpaths of JARs in lib dir. Not usable with signed JARs.
javafx.rebase.libs=false
javafx.run.height=600
javafx.run.width=800
javafx.signing.blob=false
javafx.signing.enabled=false
javafx.signing.type=notsigned
# Pre-JavaFX 2.0 WebStart is deactivated in JavaFX 2.0+ projects
jnlp.enabled=false
# Main class for Java launcher
main.class=com.javafx.main.Main
# For improved security specify narrower Codebase manifest attribute to prevent RIAs from being repurposed
manifest.custom.codebase=*
# Specify Permissions manifest attribute to override default (choices: sandbox, all-permissions)
manifest.custom.permissions=
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
native.bundling.enabled=false
platform.active=default_platform
run.classpath=${dist.jar}\:${javac.classpath}\:${build.classes.dir}
run.test.classpath=${javac.test.classpath}\:${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

ivy.classpath=lib/commons-beanutils-1.8.3.jar\:lib/commons-codec-1.6.jar\:lib/commons-collections-3.2.1.jar\:lib/commons-configuration-1.10-javadoc.jar\:lib/commons-configuration-1.10-sources.jar\:lib/commons-configuration-1.10.jar\:lib/commons-digester-1.8.1.jar\:lib/commons-jexl-2.1.1.jar\:lib/commons-jxpath-1.3.jar\:lib/commons-lang-2.6.jar\:lib/commons-logging-1.1.1.jar\:lib/commons-vfs2-2.0.jar\:lib/log4j-1.2.8.jar\:lib/maven-scm-api-1.4.jar\:lib/maven-scm-provider-svn-commons-1.4.jar\:lib/maven-scm-provider-svnexe-1.4.jar\:lib/plexus-utils-1.5.6.jar\:lib/regexp-1.3.jar\:lib/servlet-api-2.4.jar\:lib/xml-apis-1.0.b2.jar\:lib/xml-resolver-1.2.jar

更新: 这是 build.xml 文件更改为使用 Mark Hunter 提到的常春藤检索模式

<?xml version="1.0" encoding="UTF-8"?><!-- You may freely edit this file. See commented blocks below for --><!-- some examples of how to customize the build. --><!-- (If you delete it and reopen the project it will be recreated.) --><!-- By default, only the Clean and Build commands use this build script. --><project name="Naps" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
    <description>Builds, tests, and runs the project Naps.</description>
    <import file="nbproject/build-impl.xml"/>
    <property name="one-jar.dist.dir" value="/home/tester/JAVA/one-jar-ant"/>
    <import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true"/>

    <target name="-check-for-ivy">
        <available property="have.ivy" resource="fr/jayasoft/ivy/ant/antlib.xml"/>
    </target>
    <target name="-ivy-define" depends="-check-for-ivy" unless="have.ivy">
        <taskdef resource="fr/jayasoft/ivy/ant/antlib.xml" uri="antlib:fr.jayasoft.ivy.ant">
            <classpath>
                <fileset dir="${ivy.home}">
                    <include name="ivy*.jar"/>
                    <include name="lib/*.jar"/>
                </fileset>
            </classpath>
        </taskdef>
    </target>
    <target name="-ivy-retrieve" depends="-ivy-define" xmlns:ivy="antlib:fr.jayasoft.ivy.ant">
        <ivy:resolve/> <!-- Tell Ivy to resolve dependencies -->
        <ivy:retrieve conf="napsjar" pattern="lib/[artifact].[ext]"/>
        <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>

    <!-- fix ivy task -->
    <target name="-pre-jfx-jar">
        <move file="lib/JarL-NA.jar/JarL.jar" todir="lib"/>
        <delete dir="lib/JarL-NA.jar"/>
    </target>

    <!-- one-jar task -->
    <target name="-post-jfx-jar">
        <one-jar destfile="naps-one-jar.jar">
            <manifest>
                <attribute name="One-Jar-Main-Class" value="jarl.Main"/>
            </manifest>
            <main>
                <fileset dir="/home/tester/WORKSPACE/NetBeans/Naps/build/classes"/>
            </main>
            <lib>
                <fileset dir="/home/tester/WORKSPACE/NetBeans/Naps/lib"/>
            </lib>
        </one-jar>
    </target>    
</project>

这里是 ivy.xml 使用配置,虽然只是不确定为什么要改变任何东西

<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="1.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="http://www.jayasoft.org/misc/ivy/samples/ivy.xsd"
>
    <info organisation="org.naps" module="naps"/>
    <configurations>
        <conf name="napsjar" description="Jars used by application"/>
    </configurations>
    <dependencies>
        <dependency org="commons-configuration" name="commons-configuration" rev="1.10" conf="napsjar->default"/>
        <dependency org="NA"  name="JarL" rev="NA" conf="napsjar->default"/>
    </dependencies>
</ivy-module>

这些变化导致lib/JarL-NA.jar/JarL-NA.jar变成了lib/JarL.jar/JarL.jar,它仍然在lib的一个子目录中现在阻止我的简单重命名步骤表单工作。

其余依赖项如预期和以前一样位于库中。

此外,这些更改现在已阻止 nb 解析 commons-configuration,因此源无法再导入 class。

以下项目是如何设置和使用 ivy 任务的示例。您正在使用的构建文件看起来像是已生成并遵循一些较旧的使用模式。

希望对您有所帮助。

例子

此项目已自定义为使用 "local-libs" 目录作为文件存储库。这适用于一些库与源代码一起交付的场景,因为它们无法从外部存储库(如 Maven Central)获得。

├── build.xml
├── ivysettings.xml
├── ivy.xml
├── local-libs
│   └── JarL-1.0.jar
└── target
    ├── dist
    │   └── lib
    │       ├── commons-configuration-1.10.jar
    │       ├── commons-lang-2.6.jar
    │       ├── commons-logging-1.1.1.jar
    │       └── JarL-1.0.jar
    └── ivy-reports
        ├── ivy-report.css
        └── org.naps-naps-napsjar.html

在运行构建后,在"target"目录下创建了两个目录:

  1. "dist/lib":包含ivy管理的文件。检查解决任务的工作方式
  2. "ivy-reports": HTML 告诉你 ivy 如何确定依赖关系的报告

应该注意的是,我还包括了一个如何创建一个 属性 包含由 ivy 管理的类路径列表的示例。

build.xml

如果构建文件,请注意顶部的命名空间。 Ivy 不再需要明确的任务定义。如果构建服务器上不存在,还包括安装 ivy 的目标。最后注意 ivy "resolve"、"report"、"cachepath" 和 "retrieve" 任务是如何调用的:

<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">

    <!--
    ================
    Build properties
    ================
    -->
    <property name="src.dir"          location="src/main/java"/>
    <property name="resources.dir"    location="src/main/resources"/>
    <property name="test.src.dir"     location="src/test/java"/>
    <property name="build.dir"        location="target"/>
    <property name="dist.dir"         location="${build.dir}/dist"/>

    <property name="jar.main.class" value="jarl.Main"/>
    <property name="jar.file"       value="${dist.dir}/${ant.project.name}.jar"/>

    <available classname="org.apache.ivy.Main" property="ivy.installed"/> 

    <!--
    ===========
    Build setup
    ===========
    -->
    <target name="install-ivy" description="Install ivy" unless="ivy.installed">
        <mkdir dir="${user.home}/.ant/lib"/>
        <get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar"/>
        <fail message="Ivy has been installed. Run the build again"/>
    </target>

    <target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
        <ivy:resolve/>

        <ivy:report todir='${build.dir}/ivy-reports' graph='false' xml='false'/>

        <ivy:cachepath pathid="naps.path" conf="napsjar"/>
    </target>

    <!--
    =====================
    Build and run targets
    =====================
    -->

    <target name="build" depends="resolve" description="Do stuff">

        <!-- Populate a lib directory with the ivy resolved files -->
        <ivy:retrieve pattern="${dist.dir}/lib/[artifact]-[revision](-[classifier]).[ext]" conf="napsjar"/>

        <!-- Print the classpath managed by ivy -->
        <pathconvert property="naps.path.prop" refid="naps.path"/>
        <echo message="Ivy managed classpath: ${naps.path.prop}"/>
    </target>


    <!--
    =============
    Clean targets
    =============
    -->
    <target name="clean" description="Cleanup build files">
        <delete dir="${build.dir}"/>
    </target>

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

</project>

ivy.xml

注意如何使用特殊组织引用本地文件 "NA"

<ivy-module version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.jayasoft.org/misc/ivy/samples/ivy.xsd" >
    <info organisation="org.naps" module="naps"/>
    <configurations>
        <conf name="napsjar" description="Jars used by application"/>
    </configurations>
    <dependencies>
        <dependency org="commons-configuration" name="commons-configuration" rev="1.10" conf="napsjar->default"/>
        <dependency org="NA" name="JarL" rev="1.0" conf="napsjar->default"/>
    </dependencies>
</ivy-module>

ivysettings.xml

"modules" 部分告诉 ivy 使用文件系统解析器解析 "NA" 组织工件。工件模式告诉 ivy 如何解析本地文件。包含版本号总是一个好主意。

<ivysettings>
   <settings defaultResolver="central" />
   <resolvers>
      <ibiblio name="central" m2compatible="true"/>
      <filesystem name='local'>
        <artifact pattern='${ivy.settings.dir}/local-libs/[artifact]-[revision].[ext]'/>
      </filesystem>
   </resolvers>
   <modules>
      <module organisation="NA" resolver="local"/>
   </modules>
</ivysettings>