Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Symlink for dependencies in Maven assembly

I have a Maven assembly that after unpacking the tar, creates three directories each containing a /lib directory. So e.g.

folder1/lib
folder2/lib
folder3/lib

Currently, I am packing a same .jar in each of these /lib directories. Since this is a waste of space, I was wondering if I could have just one copy of that .jar and create something like a symlink for other two locations that could reference that .jar?

Thanks!

like image 330
user3645939 Avatar asked May 16 '14 19:05

user3645939


3 Answers

Here is my solution with maven-antrun-plugin for very similar situation. Zookeeper dependencies are previously placed into ${basedir}/target/package/lib by maven-dependency-plugin. Now I'm creating symlinks for all libraries into ${basedir}/target/package/lib/zookeeper/lib which point 2 dirs upper.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <id>prepare-delivery</id>
            <phase>package</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <target>
                    <!-- Prepare zookeeper layout. -->
                    <mkdir dir="${basedir}/target/package/lib/zookeeper/lib"/>
                    <apply executable="ln" dir="${basedir}/target/package/lib/zookeeper/lib" relative="true">
                        <arg value="-s"/>
                        <srcfile prefix="../../"/>
                        <targetfile/>
                        <fileset dir="${basedir}/target/package/lib" includes="**"/>
                        <mapper type="identity"/>
                    </apply>
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

Plugin management for antrun is set as following:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
</plugin>
like image 76
Roman Nikitchenko Avatar answered Sep 30 '22 11:09

Roman Nikitchenko


I believe this is unsupported in Maven packaging and assembly. Another Stack Overflow question from just a year ago asked the same thing and got the "unsupported" answer. And there have been two JIRAs on this feature (at least) that have been open for quite some time: one for the assembly plugin and one for Plexus components. I would say this the odds of this ever being directly supported are not good.

Just FYI, if I say "source project," I'll be refering to the project that assembled the tar. If I say "destination project," I'll mean the one unpacking the tar. This is assuming you have Maven projects on both sides- if that assumption is wrong, you should rely on command line utilities to do the tar-ing or untar-ing for you.

Since it sounds to me like you are unpacking the tar in the context of a Maven build, there are ways of working around this. As far as I know, the best solution if symlinking is important to you is to use either the junction plugin, the exec-maven-plugin, or the maven-antrun-plugin.

The junction plugin has the advantage of being portable, even on Windows. The problem is the project doing the unpacking must have explicit knowledge of the structure of the original structure of the tar, which is generally not desirable as it will now have to be updated should the intended symlinking that is changed. The plugin also seems to be pretty unmaintained, so there's that.

The exec plugin will allow you to call commandline utilities or scripts to do your linking, but you will have to toy with profiles to get crossplatform capabilities. The best benefit of doing it this way is that the project doing the unpacking is completely agnostic of the original structure of the tar. The details of the mechanism are in the question from a year ago that I mentioned above.

For my project, I am probably going to use antrun for Ant's symlink task- it is possible to have Ant record all symlinks to a file on the source side, and then package that file along with Maven. The receiving project can then check for the file and recreate its symlinks. This allows the symlinking intended for the tar distribution to be changed from its source project with no changes on the destination project. My project only supports OS X and Linux, so this is acceptable- you will need to decide which is best for you.

In either case, you will unfortunately have a situation where the project doing the unpacking must have knowledge about the way the tar was before being packed.

like image 30
Rob Avatar answered Sep 30 '22 12:09

Rob


You can use symlink task/goal of ant-run plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution>
            <phase>package</phase>
            <configuration>
                <target>
                    <symlink link="folder2/lib/${project.artifactId}-${project.version}.jar"
                             resource="folder1/lib/${project.artifactId}-${project.version}.jar"/>
                    <symlink link="folder3/lib/${project.artifactId}-${project.version}.jar"
                             resource="folder1/lib/${project.artifactId}-${project.version}.jar"/>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin>

If you want the symlinks to have relative path, you can give relative path in resource like below

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution>
            <phase>package</phase>
            <configuration>
                <target>
                    <symlink link="folder2/lib/${project.artifactId}-${project.version}.jar"
                             resource="../../folder1/lib/${project.artifactId}-${project.version}.jar"/>
                    <symlink link="folder3/lib/${project.artifactId}-${project.version}.jar"
                             resource="../../folder1/lib/${project.artifactId}-${project.version}.jar"/>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin>
like image 30
Nagabhushan S N Avatar answered Sep 30 '22 11:09

Nagabhushan S N