Deploy a folder hierarchy to a maven repository

Again, prompted by a Stackoverflow question, here is a means to deploy an entire directory including subdirectories to a maven repository.

I am using GMaven (groovy scripts embedded in maven), a great way to script and interact with maven without having to write plugins.

For a lot of what we’ll do, we need to access components from the underlying plexus container (Maven’s IOC system). Fortunately, GMaven provides several pre-defined variables:

project The maven project, with auto-resolving properties
pom Alias for project
session The executing MavenSession
settings The executing Settings
log A SLF4J Logger instance
ant An AntBuilder instance for easy access to Ant tasks
fail() A helper to throw MojoExecutionException

The way to access the plexus container is to call MavenSession.lookup(role), so you’lll be seeing a lot of code like this:


def repoFactory = session.lookup(
    'org.apache.maven.artifact.repository.ArtifactRepositoryFactory');

(Plexus role ids are usually equivalent to the qualified name of the interface that is returned)

My first Idea was to copy the functionality of the Maven Build-Helper Plugin‘ s attach-artifact mojo: attach artifacts to the current build, deploying or installing them as appropriate in the current maven lifecycle context. However, this mechanism relies on AttachedArtifacts, which must have the same groupId and artifactId as the containing project, which I didn’t think to be appropriate for a folder hierarchy.

Instead, I copied some of the code from the deploy:deploy-file mojo, grabbing repository information from the POM’s <distributionManagement> section.

Here are the plexus components we need:

def layout =  session.lookup('org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout');
def repoFactory = session.lookup(
    'org.apache.maven.artifact.repository.ArtifactRepositoryFactory');
def repository = repoFactory.createDeploymentArtifactRepository(
    pom.distributionManagement.repository.id,
    pom.distributionManagement.repository.url,
    layout, true );
def localRepository = session.localRepository;
def helper =
    session.lookup("org.apache.maven.project.MavenProjectHelper");
def afm = session.lookup(
    'org.apache.maven.artifact.handler.manager.ArtifactHandlerManager');
def factory = new org.apache.maven.artifact.factory.DefaultArtifactFactory();
factory.class.getDeclaredField("artifactHandlerManager").accessible = true;
factory.artifactHandlerManager=afm;
def deployer = session.lookup(
'org.apache.maven.artifact.deployer.ArtifactDeployer');

Then we grab some defaults from the <properties> block:

// initialize properties
def baseFolder = new File(pom.properties['deploy.basefolder']);
def groupId = pom.properties['deploy.groupId'];
def version = pom.properties['deploy.version'];

Now we iterate over all files, create an artifact and a temporary pom for each and deploy these using the Deployer component.


// iterate over all files recursively
baseFolder.eachFileRecurse{
    if(it.isDirectory())return;

    // use the file extension as packaging
    def packaging = it.name.replaceAll( /.+\./ , '' );
    // create the artifactId from the file's relative path
    def artifactId = it.absolutePath
        .replace(baseFolder.absolutePath, '')
        .substring(1)
        .replaceFirst( /\..*?$/ , '')
        .replaceAll( /\W+/ , '-' );

    // build a temporary artifact
    def artifact =
        factory.createBuildArtifact(
            groupId, artifactId, version, packaging );

    // create a pom file for the artifact
    def model = new org.apache.maven.model.Model();
    model.setModelVersion( "4.0.0" );
    model.setGroupId( groupId );
    model.setArtifactId( artifactId );
    model.setVersion( version );
    model.setPackaging( packaging );
    File pomFile = File.createTempFile( "mvndeploy", ".pom" );
    pomFile.deleteOnExit();
    fw = org.codehaus.plexus.util.WriterFactory.newXmlWriter( pomFile );
    new org.apache.maven.model.io.xpp3.MavenXpp3Writer().write( fw, model );
    org.apache.commons.io.IOUtils.closeQuietly( fw );

    def metadata =
        new org.apache.maven.project.artifact.ProjectArtifactMetadata(
                    artifact, pomFile );
    artifact.addMetadata( metadata );

    // deploy file
    deployer.deploy(it, artifact, repository, localRepository );
}

And here is the entire pom.xml:

<project
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>folderdeployer</artifactId>
    <packaging>jar</packaging>
    <version>SNAPSHOT</version>

    <properties>
        <!-- This is where your artifacts are -->
        <deploy.basefolder>c:\temp\stuff</deploy.basefolder>

        <!-- This will be used as groupId -->
        <deploy.groupId>my.groupid</deploy.groupId>

        <!-- this will be used as version -->
        <deploy.version>1.2.3</deploy.version>
    </properties>
    <build>
        <plugins>

            <plugin>
                <groupId>org.codehaus.groovy.maven</groupId>
                <artifactId>gmaven-plugin</artifactId>
                <version>1.0</version>
                <dependencies>
                    <dependency>
                        <groupId>commons-io</groupId>
                        <artifactId>commons-io</artifactId>
                        <version>1.4</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>deploy-files</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>execute</goal>
                        </goals>
                        <configuration>
                            <source>
                            <![CDATA[
// read components from plexus container
def layout = session.lookup(
    'org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout');
def repoFactory = session.lookup(
    'org.apache.maven.artifact.repository.ArtifactRepositoryFactory');
def repository = repoFactory.createDeploymentArtifactRepository(
    pom.distributionManagement.repository.id,
    pom.distributionManagement.repository.url,
    layout, true );
def localRepository = session.localRepository;
def helper =
    session.lookup("org.apache.maven.project.MavenProjectHelper");
def afm = session.lookup(
    'org.apache.maven.artifact.handler.manager.ArtifactHandlerManager');
def factory = new org.apache.maven.artifact.factory.DefaultArtifactFactory();
factory.class.getDeclaredField("artifactHandlerManager").accessible = true;
factory.artifactHandlerManager=afm;

def deployer = session.lookup(
    'org.apache.maven.artifact.deployer.ArtifactDeployer');

// initialize properties
def baseFolder = new File(pom.properties['deploy.basefolder']);
def groupId = pom.properties['deploy.groupId'];
def version = pom.properties['deploy.version'];

// iterate over all files recursively
baseFolder.eachFileRecurse{
    if(it.isDirectory())return;

    // packaging = file.extension
    def packaging = it.name.replaceAll( /.+\./ , '' );
    // artifactId = file.relativePath.replace '/' , '-'
    def artifactId = it.absolutePath
        .replace(baseFolder.absolutePath, '')
        .substring(1)
        .replaceFirst( /\..*?$/ , '')
        .replaceAll( /\W+/ , '-' );
    def artifact =
        factory.createBuildArtifact(
            groupId, artifactId, version, packaging );

    // create pom for artifact
    def model = new org.apache.maven.model.Model();
    model.setModelVersion( "4.0.0" );
    model.setGroupId( groupId );
    model.setArtifactId( artifactId );
    model.setVersion( version );
    model.setPackaging( packaging );
    File pomFile = File.createTempFile( "mvndeploy", ".pom" );
    pomFile.deleteOnExit();
    fw = org.codehaus.plexus.util.WriterFactory.newXmlWriter( pomFile );
    new org.apache.maven.model.io.xpp3.MavenXpp3Writer().write( fw, model );
    org.apache.commons.io.IOUtils.closeQuietly( fw );

    def metadata =
        new org.apache.maven.project.artifact.ProjectArtifactMetadata(
                    artifact, pomFile );
    artifact.addMetadata( metadata );

    // deploy file
    deployer.deploy(it, artifact, repository, localRepository );
}
                                    ]]>
                            </source>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <distributionManagement>
        <repository>
            <id>your repo id here</id>
            <url>scp://your.repo.url/here</url>
            <layout>default</layout>
        </repository>
    </distributionManagement>

</project>

Put it anywhere you want, edit the <properties> and the <distributionManagement> section and call it using

mvn package
About these ads
This entry was posted in Groovy, Maven. Bookmark the permalink.

One Response to Deploy a folder hierarchy to a maven repository

  1. Lee says:

    Using Maven 2.2.1 it had to make a few changes to get it to run. I never got it to actually deploy but that may have to do with the network proxy. Nexus never saw the POST coming in.

    1) This line had to be changed with “new” and some parens:
    OLD: fw = org.codehaus.plexus.util.WriterFactory.newXmlWriter( pomFile );
    NEW: fw = new org.codehaus.plexus.util.WriterFactory().newXmlWriter( pomFile );

    2) This line needed the same change: “org.apache.commons.io.IOUtils.closeQuietly( fw );”

    One more dependency was needed: org.codehaus.plexus:plexus-utils:2.1 (I randomly picked a version and it seemed to work. Maybe the version matters though.)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s