0

So I've been trying this for the better part of a day, and I'm so close. I have two projects, and I want to publish one as a JAR to a shared file location and then pull it in to the other project including the source and javadoc .jar files that I am generating out. The actual ivy:publish is successful and the files get correctly created in the remote file system.

However when trying to include the JAR's in my 2nd project, I can only pull in the base JAR, not the JAR's that contain the sources and javadoc.

My files are named as follows: [projectname]-[version](-[classifier]) so at the remote location I get foo-1.0.0.jar, foo-1.0.0-sources.jar, foo-1.0.0-javadoc.jar & ivy-1.0.0.xml as well as .sha and .md5 files for each JAR, but my IVY is only pulling in the foo-1.0.0.jar.

I'd like to stress that I am successfully pulling in sources and javadocs off the mavenrepo remote repository automatically and that is works really well. I just don't get why it is refusing to pull down the source & javadoc JAR's into the IVY cache when it finds and pulls the class JAR down fine from the file system.

This is the resolver pattern that I am using to pull down the files off the remote file system is:

/path/to/remote/location/[organisation]/[module]/[revision]/[module]-[revision](-[classifier]).[ext]

and the pattern that I'm using to push the files to the shared location is:

/path/to/remote/location/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]

I've been trawling the documentation and examples that people have, but the documentation may as well be written in Klingon for all the sense it makes, and the examples are either from 2010 or don't fetch sources from the file system.

Thoughts:

  • Its not a permissions issue (if it was, IVY wouldn't be able to pull anything down)
  • Its not a connection issue (see above)
  • It might be a problem with how I am publishing my project (If you think this is the case, I can provide much more detail in what I am doing with that, upon request)
  • I'm suspicious that IVY isn't pulling down (or appearing to read) the ivy-1.0.0.xml file on the remote filesystem at all. After all, that is where I'm declaring that the sources and javadoc JAR's exist.
  • Its not just this project, I've tried to follow the same process for a third project, only to have IVY only grab the class .jar file from the remote file system.
  • I could be not creating/naming files in a way that IVY is expecting to read. I had a look at the file structure that is used in mavencentral and attempted to copy how they named and laid out their files, but it doesn't work.

What I've tried:

  • Just about every combination of IVY patterns that I can think of.
  • Repeatedly deleting the cached files to see if IVY correctly resolves all files from the remote filesystem (it doesn't, it just regrabs the class JAR and generates an ivy-1.0.0.xml file in the cache directory)

Happy to post config and clarify exactly what I'm doing if you want me to etc, just drop a comment and ask for what you want.

IVY Config in second project:

<ivy-conf>

    <property name="ivy.shared.dir"
    value="/path/to/remote/repo/maven-repo/shared" />

    <property name="ibiblio-maven2-root" value="http://repo1.maven.org/maven2/"
    override="false" />

    <property name="ibiblio-spring-core-root" value="http://maven.springframework.org/"
    override="false" />

    <property name="local.pattern"
    value="[organisation]/[module]/[revision]/[module]-[revision](-[classifier]).[ext]"/>

    <property name="maven2.pattern"
    value="[organisation]/[module]/[revision]/[module]-[revision]" />

    <property name="spring.pattern" value="org/[organisation]/[module]/[revision]/" />

    <property name="maven2.pattern.ext" value="${maven2.pattern}(-[classifier]).[ext]" />

    <property name="spring.pattern.ext" value="${spring.pattern}(-[classifier]).[ext]" />

    <settings defaultResolver="default" />

    <resolvers>

        <filesystem name="shared" m2compatible="true">
            <artifact pattern="${ivy.shared.dir}/${local.pattern}" />
        </filesystem>

        <ibiblio name="maven2" root="${ibiblio-maven2-root}" pattern="${maven2.pattern.ext}"
        m2compatible="true" />

        <ibiblio name="spring" m2compatible="true" pattern="${spring.pattern.ext}"
        root="${ibiblio-spring-core-root}" />


        <chain name="internal">
            <resolver ref="shared" />
        </chain>

        <chain name="external">
            <resolver ref="maven2" />
            <resolver ref="spring" />
        </chain>

        <chain name="default" returnFirst="true">
            <chain ref="external" />
            <chain ref="internal" />
        </chain>

    </resolvers>

    <modules>
        <module organisation="company.com.au" name="name"
        resolver="default" />
    </modules>
</ivy-conf>

The only difference between the two IVY files (between both projects) is this line which is the pattern to push to the remote server:

<property name="shared-repo" 
    value="[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" />

as well as changing the tag in the resolver to shared-repo.

IVY file in the remote location:

<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
    <info organisation="company" module="simple-email" revision="1.0.0" status="integration" publication="20140924154556">
    </info>

    <configurations defaultconfmapping="default">
        <conf name="compile" visibility="private"/> 
        <conf name="test" extends="compile" visibility="private"/> 
        <conf name="master"/> 
        <conf name="runtime"/> 
        <conf name="default" extends="master,runtime"/>
        <conf name="sources" visibility="public" description="this configuration contains the source artifact of this module, if any."/>
        <conf name="javadoc" visibility="public" description="this configuration contains the javadoc artifact of this module, if any."/>
    </configurations> 

    <publications>
        <artifact name="simple-email" type="jar" ext="jar" conf="master"/>
        <artifact name="simple-email" type="source" ext="jar" conf="sources" m:classifier="sources"/>
        <artifact name="simple-email" type="javadoc" ext="jar" conf="javadoc" m:classifier="javadoc"/>
    </publications>

    <dependencies>

        <!-- Unit Testing -->
        <dependency org="junit" name="junit" rev="4.8.2" conf="test->default"/>

        <!-- Log4j Logging -->
        <dependency org="log4j" name="log4j" rev="1.2.13" conf="runtime->default;test->default;compile->default"/>

        <!-- SLF Logging -->
        <dependency org="org.slf4j" name="slf4j-simple" rev="1.6.1" conf="runtime->default;compile->default;test->default"/>
        <dependency org="org.slf4j" name="slf4j-api" rev="1.6.1" conf="runtime->default;compile->default;test->default"/>

        <dependency org="javamail" name="javamail" rev="1.4" conf="runtime->default;compile->default;test->default"/>


    </dependencies>

</ivy-module>

IVY file that gets generated in the cache:

<ivy-module version="2.0">
    <info organisation="company"
    module="simple-email"
    revision="1.0.0"
    status="release"
    publication="20140924162544"
    default="true"
/>
    <configurations>
        <conf name="default" visibility="public"/>
    </configurations>
    <publications>
        <artifact name="simple-email" type="jar" ext="jar" conf="default"/>
    </publications>
</ivy-module>

Directory Structure on remote server:

Org
|--Module
    |--Version
      |--ivy-1.0.0.xml
      |--ivy-1.0.0.md5
      |--ivy-1.0.0.sha
      |--simple-email-1.0.0-javadoc.jar
      |--simple-email-1.0.0-javadoc.jar.md5
      |--simple-email-1.0.0-javadoc.jar.sha
      |--simple-email-1.0.0-sources.jar
      |--simple-email-1.0.0-sources.jar.md5
      |--simple-email-1.0.0-sources.jar.sha
      |--simple-email-1.0.0.jar
      |--simple-email-1.0.0.jar.md5
      |--simple-email-1.0.0.jar.sha

Ivy Cache Directory structure:

Org
|--Module
   |--ivy-1.0.0.xml
   |--ivydata-1.0.0.properties
   |--jars
      |--simple-email-1.0.0.jar

Publish Task on the ANT script:

<target name="ivy-publish" depends="archive">
    <ivy:publish resolver="shared" pubrevision="${project.jar.version}" overwrite="true">
        <artifacts pattern="${dist.dir}/[artifact].[ext]"/>
    </ivy:publish>
</target>
JamesENL
  • 6,400
  • 6
  • 39
  • 64
  • You need to post your configuration and the content of the remote ivy file. Most likely this is an ivy configuration issue. You state that publishing to a Maven repo works fine. That is because ivy will derive it's configurations (see: http://stackoverflow.com/questions/7104364/how-are-maven-scopes-mapped-to-ivy-configurations-by-ivy/7116577#7116577). – Mark O'Connor Sep 24 '14 at 22:21
  • I've added the information you requested, but I've never used Maven, so I don't get what maven scopes are or how they work. – JamesENL Sep 25 '14 at 02:17

1 Answers1

3

Explanation

Theory

First of all this setup is a bit complicated, but also familiar because it's how ivy translates Maven modules into ivy ones. The problem is understanding how Maven "scopes" are translated into ivy "configurations".

How are maven scopes mapped to ivy configurations by ivy

Your remote module

Addressing your specific question I think the issue is how you are downloading artefacts. Your remote module declares the following files:

   <publications>
        <artifact name="simple-email" type="jar" ext="jar" conf="master"/>
        <artifact name="simple-email" type="source" ext="jar" conf="sources" m:classifier="sources"/>
        <artifact name="simple-email" type="javadoc" ext="jar" conf="javadoc" m:classifier="javadoc"/>
    </publications>

The magic part is the configurations. In this case you have a file associated with the following configurations:

  • master
  • sources
  • javadoc

Secondly the remote module has a rather complex set of configurations declared. Here are ones relevent to the "default" setup:

<configurations defaultconfmapping="default">
    ..
    ..
    <conf name="master"/> 
    <conf name="runtime"/> 
    <conf name="default" extends="master,runtime"/>
    ..
    ..
</configurations> 

So... Only the "master" artefact is included. This would explain why source code is excluded by default, which makes sense because normally users would want the compiled binaries.

How ivy downloads artefacts

Simple (I don't want to use configurations)

This is where we dig into the magic of dependency mappings. Most of the time users don't care about time. So to ignore them I normally recommend adding a conf="default" at the end of each dependency:

<dependency org="company" name="simple-email" rev="1.0.0" conf="default"/>

The creates the following relationship between me and the remote module:

<local "default" configuration> -> <remote "default" configuration>

In others words only give me defaults which are the compiled binaries excluding other more optional stuff like source and javadoc.

Using configurations

Once you understand configurations you're going to want to declare them locally. For example:

<configurations>
    <conf name="compile" description="Required to compile application"/>
    <conf name="sources" description="Source code"/>
</configurations>

We're stating that we have two buckets or logical groupings of dependencies.

Now we make our dependency declares more aware of our local configurations:

<dependency org="company" name="simple-email" rev="1.0.0" conf="compile->default;sources"/>

We now have 2 mappings:

<local "compile" configuration> -> <remote "default" configuration>
<local "sources" configuration> -> <remote "sources" configuration>

We can now reference or use these configurations separately in our ANT build file. For example create a classpath:

<ivy:cachepath pathid="compile.path" conf="compile"/>

Our put the sources jar inside the build directory using the retrieve task:

<ivy:retrieve pattern="build/src/[artifact]-[revision](-[classifier]).[ext]" conf="sources"/>

Example

In this contrived example I want to download the source jars into a build/src directory and the compile dependencies into a lib dir:

├── build
│   └── src
│       └── log4j-1.2.17-sources.jar
├── build.xml
├── ivy.xml
└── lib
    └── log4j-1.2.17.jar

build.xml

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

    <target name="retrieve">
        <ivy:retrieve pattern="lib/[artifact]-[revision](-[classifier]).[ext]" conf="compile"/>
        <ivy:retrieve pattern="build/src/[artifact]-[revision](-[classifier]).[ext]" conf="sources"/>
    </target>

</project>

Note:

  • The files downloaded by ivy are grouped into "configurations". Each retrieve task has a different "conf" attribute.
  • Configurations are declared in the ivy file and mappings are defined on each dependency.

ivy.xml

<ivy-module version="2.0">
    <info organisation="com.myspotontheweb" module="demo"/>

    <configurations>
        <conf name="compile" description="Required to compile application"/>
        <conf name="sources" description="Source code"/>
    </configurations>

    <dependencies>
        <dependency org="log4j" name="log4j" rev="1.2.17" conf="compile->default;sources" />
    </dependencies>

</ivy-module>

Notes:

  • Ivy file creates 2 configurations
  • The magic is the "conf" attribute of the dependency. This creates the following mappings "compile->default" and "sources->sources". This means compile dependencies come from the remote default (usual setting) and the local sources come from the remote sources.
Community
  • 1
  • 1
Mark O'Connor
  • 76,015
  • 10
  • 139
  • 185
  • That all makes sense to my half asleep brain. I'll have to have a look on Tuesday when I get back to work – JamesENL Sep 27 '14 at 08:46
  • Have a cookie for the detailed explanation – JamesENL Sep 27 '14 at 08:47
  • @JamesMassey :-) http://www.google.ie/imgres?imgurl=http%3A%2F%2Fmeetville.com%2Fimages%2Fquotes%2FQuotation-Ina-Garten-humor-Meetville-Quotes-127196.jpg&imgrefurl=http%3A%2F%2Fmeetville.com%2Fquotes%2Ftag%2Fhumor%2Fpage346&h=275&w=403&tbnid=iw4toptPJF0YvM%3A&zoom=1&docid=2GkbQk_WCMiFNM&ei=-XwmVNzML6LP7gbp1oHQCg&tbm=isch&client=ubuntu&ved=0CB8QMygAMAA&iact=rc&uact=3&dur=1456&page=1&start=0&ndsp=10 – Mark O'Connor Sep 27 '14 at 09:02
  • Your answer helped me discover why my sources and javadocs were not being pulled in. The ivy.xml that was in the cache for the simple-email project was a default generated one, and not being downloaded from the repo. Any ideas on how to get ivy to use the remote ivy.xml file rather than generate a new one? – JamesENL Oct 02 '14 at 04:09
  • I added the path to the ivy config file in the filesystem resolver and that solved the problem. Thanks for your help! – JamesENL Oct 02 '14 at 05:11