Ok, it will take you longer than five minutes, but it is possible to work the migration in parallel so that most of your team sees the conversion happen very quickly when the time is right.
Once upon a time, I was tasked with converting an existing, monolithic Ant / CVS based build to Maven 2 and Svn. This was back in the 2.0-beta-1 days (2005) so many of the tools have changed to make life easier, but I think the general process I used is still applicable to users migrating today. I'll try to focus on the generic approach and leave specific details to the best practices documented elsewhere on this blog or in the Maven book.
Migrating from Ant to Maven requires a few basic steps:
- Identify the Maven coordinates of your external dependencies. If you have a typical Ant build, you probably have a lib folder in your build tree with a pile of jars with no version. You need to figure out the Maven coordinates for this jar so you can add it as a dependency in your poms. Back when I was doing this, it was a guessing game of "I hope the latest version works since I have no way to know what version this is." Today, this is a piece of cake. You can use the checksum search in Sonatype Nexus Repository at repository.sonatype.org. This will calculate the hash in your browser and then search all the mirrors we have indexed for that jar. If it's out there, you'll find it here in seconds.
- Share your dependencies. Once you identify these dependencies, you need to find a good way to share them. You do this by setting up a repository manager and proxying the repositories you need. For any dependencies you have that aren't available publicly (commercial utilities, etc.) you will want to load these into a hosted third-party repository in your repository manager.
- Modularize your build. I had a single huge build that produced a war. This had to be decomposed into the appropriate jars so we could leverage Maven's ability to reuse artifacts and not require all developers to build the entire world. How this decomposition goes is completely dependent on your architecture. I was able to break it down pretty far, but ended up with a little pile of code that couldn’t be separated more without introducing circular dependencies. We decided to deprecate this code in place. That is to say that any significant changes and enhancements to this code would be done by creating a new module. Eventually the "common" module would (and did) fade away.
- Create poms for each module. To do this means understanding the actual dependencies of each piece of code you pull apart. I used a tool to scan the byte code and tell me about the classes in there and then I had to go locate the classes in the jars manually. Today you can use dependency:analyze to do this for you. This goal is able to tell you about jars you depend on directly but haven't listed, as well as things you have listed as dependencies but aren't. Today, I would approach this by putting all my external dependencies in each pom and run analyze on it. This will tell you quickly which ones you don't need (and possibly some you forgot). Then you can do a similar process with your internal dependencies.
Since the migration and modularization would take time to work out (not to mention I had to learn this new Maven thing in parallel), I decided that a parallel process was required. We were also cutting over to a new SCM tool (cvs to svn). In hindsight, this may have made the Maven conversion easier because we decided to not migrate the history. This allowed me to setup a parallel SCM as well.
This is how the process went:
-
Checkout from CVS the current project.
-
I created the new Mavenized folder structure in SVN. This obviously migrated over time as we decomposed the code.
-
Only the pom.xml and patch files where added to SVN.
-
Scripts where created that moved the source folders from the CVS checkout, sometimes apply source patches and place them into the appropriate places in the SVN folder structure.
Obviously there was a lot of manual experimentation involved in finding where the files needed to be, but the idea was that once I knew where the files needed to be, it would be captured in a script. This allowed me to be able to constantly keep pace with the ongoing development in CVS as I refined my poms and file structures in parallel. Ultimately we were able to produce a matching set of artifacts from Maven that could be tested against the equivalent Ant built ones to be sure everything was right.
These scripts had a second purpose, which was when it came time to make the actual big-bang conversion, it was very quick and easy (and well tested). Everyone committed any open changes to CVS, I updated, ran my script, did a recursive svn add and svn commit and we flipped from Ant/CVS to Maven/Svn in less than five minutes. (as viewed by the developers…the actual process took an elapsed two months as I worked on it in between other things).
Written by Brian Fox
Brian Fox is a software developer, innovator and entrepreneur. He is an active contributor within the open source development community, most prominently as a member of the Apache Software Foundation and former Chair of the Apache Maven project. As the CTO and co-founder of Sonatype, he is focused on building a platform for developers and DevOps professionals to build high-quality, secure applications with open source components.
Explore All Posts by Brian Fox