Organising Ivy repos

Edit: since I migrated most of my projects to maven this is less relevant to what I do now.

This is about a trick I use to organise my open source projects.
Unlike in-house projects, open source projects have to allow anyone to download them and build them so they cannot, for example, be dependent on some local library to resolve dependencies.
I use Apache Ivy as my dependency manager and ivyroundup as my public repository. So when my project’s ivy configuration needs to resolve, say, slf4j, it can find it and download it automatically. I don’t need to keep all the jar files in my project itself, which means I don’t need to maintain them etc. So this is good.
If I only had one project we could stop there, but I have several and some are dependent on others. So I might make a change to madura-date-time which is dependent on maduraconfiguration. In the process I might identify a change to maduraconfiguration I need to make. So I do that, publish maduraconfiguration to ivyroundup, then go make my change to madura-date-time and… find I need to make another change to maduraconfiguration. Oops.
Clearly I need a more efficient way to do this and I have one, but before we go there we need to understand that these projects are all in Eclipse, and that means they end up having their dependencies resolved two different ways.
For the official build I use Apache Ant. There is a build.xml file which resolves dependencies, compiles everything, runs the unit tests, packages it into a jar file and even uploads it to Google. It also generates the required configuration files for ivyroundup. You don’t need Eclipse to run this, just a Java JDK and Ant.
But for moment by moment development Eclipse runs compiles and, when necessary, resolves dependencies using the same ivy.xml and ivysettings files that Ant uses. But how it finds the repository is a subtly different.
The ivysettings file is an xml file that tells Ivy how to find the repository. This is what mine looks like:

<ivysettings>
    <property name=”ivy.cache.dir” value=”${user.home}/.ivy2″ />
    <property name=”roundup-repository” value=”http://ivyroundup.googlecode.com/svn/trunk” override=”false” />

    <settings  
            defaultResolver=”libraries”           
            defaultConflictManager=”all” >

    </settings>
    <caches
        checkUpToDate=”false”
        defaultCacheDir=”${ivy.cache.dir}/cache” />

    <namespaces>
        <namespace name=”maven2″>
        </namespace>
    </namespaces>

    <resolvers>
        <chain name=”libraries”>
            <packager name=”roundup” buildRoot=”${user.home}/.ivy2/packager/build” resourceCache=”${user.home}/.ivy2/packager/cache”>
                <ivy pattern=”${roundup-repository}/repo/modules/[organisation]/[module]/[revision]/ivy.xml”/>
                <artifact pattern=”${roundup-repository}/repo/modules/[organisation]/[module]/[revision]/packager.xml”/>
            </packager>
        </chain>
    </resolvers>
</ivysettings>

The resolvers specify where the repository is. You can have more than one but I only need one just now. It uses a property called “roundup-repository” which is defined in the third line and, of course, it points to ivyroundup.
Now comes the tricky part. I want to point to a local repository instead of ivyroundup but I want nothing in the project that I commit (and which others would download) to see that repository. I just know that if it is something I have to edit out before I commit I will forget.
When building under Ant this is easy. I can just define an Ant runtime property in Eclipse that overrides “roundup-repository” so if I launch the build from Eclipse the override value will be used, ie my local repo. Since I define this value as part of the workspace configuration there are no files to accidentally commit because there is nothing in the project. It also means anyone downloading the project doesn’t have to set that up.
But when the IvyDE plugin runs it does not see the Ant properties because it isn’t Ant (fair enough). There are two ways to override the property. I can define project level properties or workspace level properties. Project level properties will mean I have a file in the project which I have to edit before I commit. So I reject that approach. Workspace level properties are only available if I have a workspace level ivysettings file. But I don’t want to do that because that means anyone downloading the project will need to know how to set that up because, of course, it isn’t committed.
There is one other way and that is the trick.
I start Eclipse with this in the command line:

-Droundup-repository=file:///home/roger/madura3/ivyroundup-trunk

which points to where my local repo lives. Note that this has to be on the command line after the -vmargs option.
With that in place IvyDE will use my local repo instead of the remote one.
And there is nothing in my project that specifies this so nothing to remember to change when I commit.
What about Ant? Is this enough to tell Ant where to find the repo as well?
Sadly no. I still need an Ant property defining the value for roundup-repository or it breaks. But actually I need a few other Ant properties anyway and I have them in an external file.
Why do I add the symbol to the command line and not to the eclipse.ini file? Well, that is because I run a number of workspaces all of which launch the same Eclipse and hence use the same ini file. But only one of my workspaces needs the roundup-repository defined in this way. Others need other stuff. So the setting does not belong in the ini file.
So, to recap, I have a workspace that uses a local ivy repo without any of the projects in the workspace knowing its location. They only thing they know about is the remote repo, which is all I want people who download it to know about because that is the repo they can access.

Leave a Reply

Your email address will not be published. Required fields are marked *