12

So, I have a war project with several dependent jars that are not available in any repository. Up until recently, I'd been keeping them in src/main/webapp/WEB-INF/lib, and adding them to the pom with system scope.

I get that that's problematic, so I'm looking to clean up my build. I've semi-manually installed the jars into my .m2/repository via the install:install-file plugin. That's great for me, but what about the other people on my team? We're tiny, and setting up Nexus isn't really an option for us. I've resorted to adding comments to the pom.xml explaining how to run install:install-file for each jar.

I'm OK with the install:install-file solution, but I'd still like to include these artifacts in my project's version control, and not merely have them sprinkled about my filesystem.

Keeping them in src/main/webapp/WEB-INF/lib doesn't work, since that automatically adds them to the resulting war artifact (digression: if maven would simply go ahead and add them to the classpath here I'd be done, no need for install:install-file!)

Question: is there a sanctioned place in the maven directory layout where I can tuck these .jar files, just so that I can keep them as part of my project?

I do realize what's going on here- Maven is attempting to keep dependent jars outside of my build so that when other projects depend on my build, they can resolve the transitive dependencies. That's great for open-source projects that are going into the public maven repos, but I'd bet that the vast majority of people using Maven are working on "leaf" projects such as this, and it would be really handy to have a way to include jar files as part of the project without jumping through so many hoops.

Community
  • 1
  • 1
George Armhold
  • 30,824
  • 50
  • 153
  • 232
  • 3
    Setting up Nexus is pretty easy. I have an instance running just for myself at home. – ColinD Mar 14 '11 at 16:07
  • Would it be too overkill to create a local repository with nexus? You can use it to proxy to the all the maven repos and to keep those 3rd party jars. – Augusto Mar 14 '11 at 16:09
  • 3
    Sure, I could install Nexus. But then I'd had to ask everyone who touches this project to do the same. Or else set it up on a server, back it up, worry about security, etc. It just seems like a very cumbersome solution for dealing with a couple of custom jar files. – George Armhold Mar 14 '11 at 17:09
  • it isn't "jumping through hoops" if you use Maven the way it is intended to be used. The `maven-release-plugin` along with the proper `maven-scm-plugin` and `` directives in your `pom.xml` makes all this transparent. –  Mar 14 '11 at 18:05
  • see my answer, you don't have to ask everyone who touches the project to do anything, it is all in the `pom.xml` that is used to build the project. And if editing their `settings.xml` is too much to ask, then just embedded the repository information in the `pom.xml`, which is bad practice but low barrier to entry. –  Mar 14 '11 at 18:20

5 Answers5

5

If setting up Nexus or just a simple fileserver repo as suggested by Jan is really too much trouble, here are some other options:

  • Simply include the JARs and a script that'll install them all in a directory of your choosing in version control. No need for the Maven structure to sanction it.
  • Use your version control system as a host for the repository, either on a branch by itself in your main project or as a separate project. Let any backup, security, etc. you already have on version control apply to the repository without including the jars in the set of files that are actually being checked out and committed.
  • Include the jars in a folder that acts as a mini-repository that is checked out with the rest of the code. Have pom.xml point to that folder as a repository it uses. I'm not 100% sure this is possible, but it seems likely that it is.
ColinD
  • 108,630
  • 30
  • 201
  • 202
  • We follow your first suggestion. Maven does not support your last suggestion. – Derek Mahar Mar 14 '11 at 18:12
  • +1: The last suggestion appears to work as well (using Maven 2.2.1). – Lars Mar 14 '11 at 22:01
  • 2
    I almost want to give you a +1 simply for not responding with "But really, setting up Nexus isn't hard." :-) On some (many?) projects setting up a tool like Nexus simply isn't an option. And keeping artifacts outside the main source repo just isn't a good idea if you don't have the team/resources to maintain that external repository as carefully as you would your source repo. People using ant just stuff jars in a lib directory and they're done. I often wish that Maven would adopt a "simple things should be simple" mantra. Thanks for your response. – George Armhold Mar 20 '11 at 23:34
  • 1
    We're currently doing the first option. This is unsatisfactory to me because it still introduces steps that need to be performed before a build can be done in a way that Maven doesn't know about. If you set up a CI server or remote builds somewhere, for example, you can't just point it at the Maven project and let it do things normally. It seems to me that this is an incredibly common use case, and Maven pretends it doesn't exist. – Lyle Aug 26 '11 at 00:53
3

There are lots of good answers here already, and you should strongly consider setting up a repository manager such as Archiva for your group as it'll provide other benefits both now and over time.

However, to directly answer your question, here is a pattern for storing dependencies in version control with Maven: http://brettporter.wordpress.com/2009/06/10/a-maven-friendly-pattern-for-storing-dependencies-in-version-control/

Please keep in mind the caveat that it limits the project to being used self-contained itself - if you start wanting to share it as a dependency for other Maven projects you'll still need a repository set up.

Brett Porter
  • 5,827
  • 27
  • 25
2

I think the best solution in your case would be to setup an internal repository. There is no need to setup whole Nexus at first. Any simple webserver will be sufficient or shared folder somewhere.

Check the Maven DOC on howto set up an internal repository.

Derek Mahar
  • 27,608
  • 43
  • 124
  • 174
Jan Zyka
  • 17,460
  • 16
  • 70
  • 118
  • But what if an internal repository is not an option? – Lars Mar 14 '11 at 17:37
  • 2
    Maven includes install:install-file just for this purpose. How hard it is to put ~/.m2/repository to /network/maven/repository? Maybe nexus is overkill, maybe HTTP is overkill, but file servers? How are those ever not an option? – Chris K Mar 14 '11 at 17:45
  • 1
    @Chris In a sufficiently complex company the source control server may be the only server accessible to all interested parties; and while long term an internal maven repository may be the best option, something is needed to bridge the interim. – Lars Mar 14 '11 at 17:53
  • 1
    @Lars: A sufficiently complex company with people using Maven should absolutely be using some kind of internal repository, not just to provide 3rd party artifacts that aren't available in public repositories but also to allow sharing of internal artifacts between projects. Using Maven implies the need for a repository in addition to source control. – ColinD Mar 14 '11 at 17:58
  • 1
    @Lars: even if that were true, you could use SCS as your repository, completely external to maven. – Chris K Mar 14 '11 at 18:02
  • 1
    @ColinD I agree, that is how it should be. But life is not always so kind, evidenced by the fact that this question is asked over and over. - @Chris Isn't that what the OP asked, how to access artifacts checked into the source control system? install:install-file works, but appears rather clunky. – Lars Mar 14 '11 at 18:23
  • Besides being tedious `install:install-file` is a very error prone way of doing things, and if every developer is having to do this, somebody is going to typo something edit the `pom.xml` to reflect their non-standard groupId or artifactId or update the version and break everything up the chain. –  Mar 14 '11 at 18:31
  • 1
    Not that I have actually tried, but can you not point a entry to __inside__ the SCM working directory. E.g. file:///${basedir}/projectrepo ? – Bittrance Mar 14 '11 at 18:33
2

At my company we are using Archiva, it is by far the simplest Repository Manager to set up and maintain. Especially if you go with the stand-alone based version. The each developer just sets up a profile in their ~/.m2/settings.xml file to point to the internal repository. If this is too much trouble, just put the internal repository in the <repositories/> in the pom.xml directly, but that is really bad practice. If the repository url ever moves, you have to update all your projects pom.xml files. Where as using settings.xml puts that burden on the developer to update their local configuration.

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <profiles>
        <profile>
            <id>internal</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <repositories>
                <repository>
                    <id>mycompany.internal</id>
                    <name>Internal Release Repository</name>
                    <url>http://maven.mycompany.com/repository/internal/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                    </snapshots>
                </repository>
                <repository>
                    <id>mycompany.snapshots</id>
                    <name>Internal Snapshot Repository</name>
                    <url>http://maven.mycompany.com/repository/snapshots/</url>
                    <releases>
                        <enabled>false</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>
        </profile>
    </profiles>


    <servers>
        <server>
            <id>internal</id>
            <username>guest</username>
        </server>
        <server>
            <id>snapshots</id>
            <username>guest</username>
        </server>
    </servers>

</settings>

If setting up a Repository Manager is too much trouble, I think you need to reconsider the alternative of manually adding stuff to your local repository by hand, which is very error prone and time consuming. I run an Archiva instance for my personal development just because it is so easy to add the release plug in and manage versions without having to remember all the arcane -D options required to add stuff to your local repository on every machine. Copying the ~/.m2/settings.xml file is super easy and if it works on one machine it works on all of them.

Here is what you add to your pom.xml to enable automatically doing releases and pushing artifacts to a repository, in my case it is Archiva.

<distributionManagement>
   <repository>
       <id>internal</id>
       <name>Internal Archiva Repository</name>
       <url>http://maven.mycompany.com/repository/internal/</url>
       <layout>default</layout>
       <uniqueVersion>false</uniqueVersion>
   </repository>
   <snapshotRepository>
       <id>snapshots</id>
       <name>Internal Archiva Repository</name>
       <url>http://maven.mycompany.com/repository/snapshots/</url>
       <layout>default</layout>
       <uniqueVersion>false</uniqueVersion>
   </snapshotRepository>
</distributionManagement>

Then all you do is mvn clean release:prepare to automatically update your pom.xml version check in, tag and optionally branch the release and package all the artifacts, and then mvn release:perform to push the artifacts to the remote repository and check in the newly versioned pom.xml and you are ready for the next version to start development.

Snapshots got to snaphots and Releases go to internal automatically with the release plug in. You do have to configure the scm plug in as well, but that is just a few lines of configuration that you only have to touch once as well.

This is what it looks like for git, we are using Gitorious as our git Repository Manager

<scm>
    <connection>scm:git:git://gitorious.mycompany.com:myproject/myproject.git</connection>
    <developerConnection>scm:git:ssh://git@gitorious.mycompany.com/myproject/myproject.git</developerConnection>
    <url>http://gitorious.mycompany.com/myproject/myproject</url>
</scm>

An old desktop computer running Linux can handle repository duties like this for a development team without having to involve procurement and IT.

2

I have not used this in real life, but it seems to be working: simply stick a repository layout inside your source tree (using install:install-file, I suppose) and and check it in. Use a entry to point to that repo. pom like so:

<?xml version="1.0" encoding="utf-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>
  <name>Depending project</name>

  <groupId>com.example</groupId>
  <artifactId>dependent</artifactId>
  <version>0.9</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>dependency</artifactId>
      <version>0.9.3</version>
      <type>jar</type>
    </dependency>
  </dependencies>

  <repositories>

    <repository>
      <id>project-specific-deps</id>
      <name>project-specific-deps</name>
      <url>file:///${basedir}/repo</url>
    </repository>

  </repositories>

</project>

Example tree like so:

.
|-- pom.xml
|-- repo
|   `-- com
|       `-- example
|           `--dependency
|               |-- 0.9.3
|               |   |-- dependency-0.9.3.jar
|               |   |-- dependency-0.9.3.jar.md5
|               |   |-- dependency-0.9.3.jar.sha1
|               |   |-- dependency-0.9.3.pom
|               |   |-- dependency-0.9.3.pom.md5
|               |   `-- dependency-0.9.3.pom.sha1
|               |-- maven-metadata.xml
|               |-- maven-metadata.xml.md5
|               `-- maven-metadata.xml.sha1
|-- src
|   `-- main
|       `-- java
|           `-- com
|               `-- example
|                   `-- dependent
|                       `-- Foobar.java

How does that sound?

For completeness:

$ mvn -version
Apache Maven 2.2.1 (rdebian-4)
Java version: 1.6.0_20
Java home: /usr/lib/jvm/java-6-sun-1.6.0.20/jre
Default locale: sv_SE, platform encoding: ISO-8859-1
OS name: "linux" version: "2.6.32-3-686" arch: "i386" Family: "unix"
Bittrance
  • 2,202
  • 2
  • 20
  • 29