Integrate ant with dbdeploy not in the classpath
2009/01/26 5 Comments
The need for a schema versioning system at LocaModa finally became a priority this sprint so I’ve spent the past few days researching and diving into implementation. After comparing LiquiBase, dbdeploy, MIGRATEdb, and dbmigrate I settled on the simple SQL driven solution that dbdeploy provides and started integrating it with our Ant build. Pramod Sadalage over at Agile DBA put up a nice post on the basics but I quickly hit a wall, the MySQL driver was not in my classpath.
As I mentioned earlier we are using Ivy for our dependancy management which makes it difficult to throw jars into the Ant classpath since they are automatically downloaded at build time. So far this hasn’t been an issue since most Ant tasks allow you to specify the classpath as a parameter within the task. Dbdeploy does not. Goggling around I quickly found a posting that suggested patching the dbdeploy ant task as the only way to go, so off I went. However, a few hours later, after wandering through the Java classloader abyss I was stymied.
I backed out of the changes and decided a different tactic was needed; back to Goggle I went. This time I came across a post which suggested all I needed was to add the jar to the taskdef classpath Could it really be that easy? Switching back to my build.xml I doctored up the dbdeploy taskdef, kicked off a build and sure enough the damn thing worked.
So, if you want to centrally manage your ant dependencies, just remember to add the necessary classpath references to your taskdefs, like so:
<taskdef name="dbdeploy"
classname="net.sf.dbdeploy.AntTarget"
classpath="${dbdeploy.jar}:${mysql-connector.jar}"/>

You might also try the classpathref attribute for taskdef so that you can define you classpath in a “path” element and use the same classpath path element for other things. This way you can add stuff to the single path element and all of the other things that use that for the classpath get updated.
Nice post.
I actually do. The real code is:
<taskdef name=”dbdeploy”
classpathref=”dbdeploy.path”
classname=”net.sf.dbdeploy.AntTarget”/>
Where dbdeploy.path is set by:
<ivy:cachepath pathid=”dbdeploy.path”
conf=”dbdeploy” />
Which in turn comes from the dbdeploy conf in ivy.xml config. But I didn’t want to dive into that in the post.
It’s driving me CRAZY! :
It works fine for something simple like :
This set up will put the mysql-connector.jar into the lib dir, and everything is good, but if the dependency is more complex i.e. Spring than it will additionally retrieve all of it’s dependencies and place them into the lib as well.
This seems abvious because this is the purpose of ivy in the first place, but what happens if one of the jars happens to have a conflict with something else once deployed, i.e. with Tomcat?
For example :
This will retieve jars that will pose conflics with Tomcat once deployed, so I have to end up deleting like 20 jars for everything to settle down.
If all I want is spring.jar or spring-webmvc.jar how can I do this?
Thanks.
Oh! Well it chopped out my code. Sorry about that.
<dependency org="org.springframework" name="org.springframework.web" rev="2.5.6.SEC01" /> <ivy:retrieve pattern="${lib.dir}/[artifact].[ext]"/>This will retrieve spring-web.jar in addition to like 20 others, but some pose conflicts, so how do I retrieve just the spring-web.jar?
Hopefully the code is visible this time.
Sorry for the slow response, didn’t see your comment in here. I don’t think there is a way to just get the single jar, at least not that I know of. The whole point is that Ivy gets all the dependancies for you.
My guess here is that, because tomcat is not under ivy, that you have jar conflicts. Ivy is great at resolving conflicts between all the jars you have listed in it but it cant deal with jars it doesn’t know about.
One hack of a way would be to download the single jar you want and have ivy get it from your hard drive or scm by editing the ivysettings.xml to add the path to the jar in the list of places ivy will look for the jar. That way it won’t know about the other dependancies. I’ve used this pattern for things that are not in a maven repo but it might work here.