mavenmaven-nar-plugin

separately publish maven attachments


I'm building NARs on multiple platforms (Mac and Windows). The build is complicated and can't be done via the Maven NAR plugin as such, but I'm building the nar files myself and using the mvn command-line tool for deployment.

The typical way to do deployment is in one shot, e.g.

mvn deploy:deploy-file \
    -Dfile=foobar.jar \
    -Dpackaging=jar \
    -Dfiles=foobar-x86_64-MacOSX-gcc-shared.nar,foobar-x86_64-Windows-MSVC-shared.nar \
    -Dclassifiers=x86_64-MacOSX-gcc-shared,x86_64-Windows-MSVC-shared \
    -Dtypes=nar,nar \
    -DgroupId=com.example \
    -DartifactId=foobar \
    -Dversion=1.0.0-SNAPSHOT \
    -Durl=$URL \
    -DrepositoryId=nexus 

However, because the builds are running on different boxes, the publishing step can't happen in one shot. Ideally, I'd like to be able to "append" the attachments to the primary artifact as the builds finish. ie.,

Run this once:

mvn deploy:deploy-file \
    -Dfile=foobar.jar \
    -Dpackaging=jar \
    -DgroupId=com.example \
    -DartifactId=foobar \
    -Dversion=1.0.0-SNAPSHOT \
    -Durl=$URL \
    -DrepositoryId=nexus 

Then on the Mac build slave:

mvn deploy:deploy-file \
    -Dfiles=foobar-x86_64-MacOSX-gcc-shared.nar \
    -Dclassifiers=x86_64-MacOSX-gcc-shared \
    -Dtypes=nar \
    -DgroupId=com.example \
    -DartifactId=foobar \
    -Dversion=1.0.0-SNAPSHOT \
    -Durl=$URL \
    -DrepositoryId=nexus 

Then on the Windows build slave:

mvn deploy:deploy-file \
    -Dfiles=foobar-x86_64-Windows-MSVC-shared.nar \
    -Dclassifiers=x86_64-Windows-MSVC-shared \
    -Dtypes=nar \
    -DgroupId=com.example \
    -DartifactId=foobar \
    -Dversion=1.0.0-SNAPSHOT \
    -Durl=$URL \
    -DrepositoryId=nexus 

The first command works fine, of course. But the two build slave commands fail with

The parameters 'file' for goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy-file are missing or invalid

because it thinks it needs the primary artifact.

How can I specify that I'm appending to the publication, not creating an entirely new one?


Solution

  • because the builds are running on different boxes, the publishing step can't happen in one shot.

    If you are using a CI server like Jenkins to perform your builds, you can publish the artifacts from each slave and then access them via a downstream job on the master node.

    This is how we solve the issue in the ImageJ project: we have our Jenkins aggregate all the build artifacts, then deploy them all at once. First, the ImageJ-launcher job—a multi-configuration project—builds the code using the appropriate slaves, archiving the relevant artifacts (which transfers them to the master node's file system). Then the ImageJ-launcher-deploy job copies the archived artifacts from each configuration into a single directory for deployment in one shot.

    In case it helps, here is the portion of the ImageJ-launcher-deploy shell script responsible for copying the NAR artifacts into one place:

    masterDir=workspace/label/master/target &&
    axesDirs=configurations/axis-label/*/builds/$buildNumber/archive/target &&
    : copy the nar/**/* files from all axes to master &&
    for path in $axesDirs/nar/*/bin/*/*
    do
            file=${path#$axesDirs/} &&
            if test -f $masterDir/$file
            then
                    # we ignore everything except Linux in the master
                    case "$path" in
                    */master/*Linux*)
                            ;;
                    */master/*)
                            continue
                            ;;
                    esac
    
                    cmp $path $masterDir/$file && continue
                    printf 'Artifacts disagree:\n%s\n%s\n\n' $path $masterDir/$file
                    errors=$(($errors+1))
            else
                    target=$masterDir/$file &&
                    mkdir -p ${target%/*} &&
                    cp $path $target
            fi
    done
    

    You may not even need to copy the artifacts if -Dfiles supports a list of files in different directories—just build up the list of files in the for loop, and finish with the mvn deploy:deploy-file invocation you gave above.

    See also this answer for further details on the ImageJ-launcher Jenkins configuration.