Tuxxy_Thang
Tuxxy_Thang

Reputation: 189

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

I am not that experienced with ivy and not sure how to solve this problem, which I probably caused myself by not understanding ivy.

so I have this in my ivysettings.xml to use a local filesystem 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 exsists in /home/tester/JAVA/tester-libs/

my dependencies are set in ivy.xml as

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

which resolves the dependency but where all the other jars like commons-configuration are placed in lib/ during the build, my jar is placed in lib/JarL sub-directory.

I want JarL to be placed in lib/ like the other dependencies and have no idea what to do. I hacked these scripts together from other answers I found on the net.

Ivy is just too in-depth for me. I not want to take months out of my life to learn yet another tool. I just want easy lazy development where I concentrate on the problem at hand not the dev tools.

UPDATE:

For the moment I have had to add the following 2 lines to the packing step in build.xml to get around this problem but it is a silly fix.

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

UPDATE: added build.xml as per Mark's request

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

and this is the nb properties file it loads

#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

UPDATE: Here is build.xml file changed to use an ivy retrieve pattern as mentioned by 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>

here's ivy.xml using configurations, htough there is only so not sure why that should change anything

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

These changes have resulted in lib/JarL-NA.jar/JarL-NA.jar becoming lib/JarL.jar/JarL.jar, which is still in a sub-directory of lib and now prevents my simple rename step form working.

The rest of the dependencies are in lib as expected and as they were before.

Addtionally, these changes have now preventd nb from resolving commons-configuration so the source can no longer import the class.

Upvotes: 1

Views: 2285

Answers (1)

Mark O&#39;Connor
Mark O&#39;Connor

Reputation: 77951

The following project is an example of how to setup and use ivy tasks. The build file you're using looks like it was generated and follows some older usage patterns.

Hope it helps.

Example

This project has been customized to use a "local-libs" directory as a file repository. This caters for scenarios where some libs are shipped alongside the source because they're not available from an external repository like 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

After running the build two directories are created under the "target" directory:

  1. "dist/lib": Containing the files managed by ivy. Check how the resolve task works
  2. "ivy-reports": HTML report telling you how ivy determined the dependencies

It should be noted I also included an example of how to create a property containing a list of the classpath managed by ivy.

build.xml

Pay attention to the namespace at the top if the build file. Ivy no longer needs an explicit taskdef. Also include a target that installs ivy if it's not present on the build server. Finally note how the ivy "resolve", "report", "cachepath" and "retrieve" tasks are called:

<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

Note how local files are referenced using the special organisation "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

The "modules" section tells ivy to resolve "NA" organisation artifacts using the file system resolver. The artifact pattern tells ivy how to resolve local files. Always a good idea to include a version number.

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

Upvotes: 4

Related Questions