A layout for maven project with a patched dependency - maven-2

Suppose, I have an opensource project that depends on some library, that must be patched in order to fix some issues. How do I do that? My ideas are:
Have that library sources set up as a module, keep them in my vcs. Pros: simple. Cons: some third party sources in my repo, might slow down build process, hard to find a patched place (though can be fixed in README)
Have a module, like in 1, but keep patched source files only, compile them with orignal library jar in classpath and somehow replace *.class files in library jar on build. Pros: builds faster, easy to find patched places. Cons: hard to configure, that jar hackery is non-obvious (library jar in repository and in my project assembly would be different)
Keep patched *.class files in main/resources, and replace on packaging like in 2). Pros: almost none. Cons: binaries in vcs, hard to recompile a patched class as patch compilation is not automated.
One nice solution is to create a distinct project with patched library sources, and deploy it on local/enterprise repository with -patched qualifier. But that would not fit for an opensourced project that is meant to be easily buildable by anyone who checks out its sources. Or should I just say "and also, before you build my project, please check out that stuff and run mvn install".

One nice solution is to create a distinct project with patched library sources, and deploy it on local/enterprise repository with -patched qualifier. But that would not fit for an opensourced project that is meant to be easily buildable by anyone who checks out its sources. Or should I just say "and also, before you build my project, please check out that stuff and run mvn install".
This is what I would do (and actually what I do) for both a corporate and an opensource project. Get the sources, put them under version control in a distinct project, patch them, rebuild the patched library (and include this information in the version, something like X.Y.Z-patched), deploy it to a repository (you could use SVN for this, a la Google Code1), declare the repository in your POM and update the dependency to point on your patched version.
With this approach, you can say to your users: check out my code and run mvn install and they will just get the patched version without any extra action. This is IMHO the cleanest way (not error prone, no class path order mess, no increase of the build time, etc).
1 Lots of people are deploying their code to their hosted subversion repository (how-to in this post).

One nice solution is to create a distinct project with patched library sources, and deploy it on local/enterprise repository with -patched qualifier. But that would not fit for an opensourced project that is meant to be easily buildable by anyone who checks out its sources. Or should I just say "and also, before you build my project, please check out that stuff and run mvn install".
I'd agree with this and Pascal's answer. Some additional notes:
you may use dependency:unpack on the original artifact and then combine that with your compiled classes if you don't want to rebuild the whole dependant project
in either case, your pom.xml will need to correctly represent the dependencies of that library
you can still integrate this as part of your project's build to avoid the 'deploy to a repository' step
make sure you honour the constraints of the project's license when doing all this!

Related

What exactly is groovy-sql and are there other modules like it?

It's a .jar available in various versions at Maven Repo.
But what category is it? It is published by org.codehaus.groovy, the same outfit that I get my groovy-all dependency from. I also find that import groovy.sql doesn't work in a script unless I specifically include this dependency. So it would appear not to be part of the core language.
Outside a Gradle context I find that I have to manually put the .jar file under ~/.groovy/lib in order to use it. If I put the wrong version (e.g. 2.5.9 for 3.0.2) under ~/.groovy/lib the script won't run... even if I'm not using groovy.sql at all!
Is this a "dependency"? It seems a typically powerful and hassle-free Groovy way of manipulating databases. Are there any other powerful add-on (non-core) Groovy .jar file modules like this, which have to be manually placed under ~/.groovy/lib, that I should know about?
groovy consists of subprojects:
https://github.com/apache/groovy/tree/master/subprojects
and groovy-sql one of the subprojects
all subprojects are published in maven as separate libraries
prior to version 2.5 there was groovy-all-XX.jar that includes all other groovy libraries
https://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/2.4.19/
however starting from v 2.5 groovy-all represented by groovy-all-XX.pom that depends on all other groovy libraries
https://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/2.5.0/
so, to include all groovy features you have to specify groovy-all in your maven/gradle/... dependency
and finally useful site to dig dependencies:
https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all/3.0.2

How can I use maven to build a tarball for a project?

OK, lemme set the stage. I have a parent pom, project_maven, that contains 3 modules in its POM, project_common, project_explode, and project_client. project_client has dependencies on both project_common and project_explode. project_client also contains an /ext directory, which contains third-party executables, scripts, etc.
In our current Ant build of the project, there is a target, build-client-tarball, that copies the /ext directory to the build directory, copies the project_common.jar and project_explode.jar files into specific locations in the build dir, and tarballs the whole thing.
I'd like to duplicate this behavior in maven without having to resort to calling the ant tasks. From what I can tell, it looks like the assembly plugin might be the way to go, but I'm having trouble figuring out how to get it to work. Seems like I would need a custom assembly descriptor? Anybody have any boilerplate or examples I can work from?
You need to use the Maven Assembly plugin. It's worth the effort to investigate it. It will do exactly what you need.
You can use it to include dependencies and sources. Have a look at this link. There're a bunch of sample assembly descriptors there. You need to define a format tar in order for it to produce a tar for you. In addition, you also need to define <dependencySets/> in order to include the modules you mentioned.

Integrating Maven & Non-maven projects

I'm currently working on two projects simultaneously:
My main project (built with maven)
A spike of an open source project, which my main project depends on (not build with maven)
How do I set up maven to use the OSS project as a dependency with the least amount of friction, given that I'm often developing the two in tandem?
I can think of several solutions:
Mavenize the existing OSS project. This is of course the "ideal" option but often not feasible (even if you introduce the new build system in parallel of the existing one). The project has likely an existing project structure that differs from Maven's standard layout. Changing the existing layout and build script may not be desired by developers, adapting a Maven build to use a non standard layout can be painful. In both case, you're screwed.
Wrap the existing Ant build with Maven. This can be nice if you want to include the build of the OSS project in the lifecycle of your project and have both of them built in one step. You can check this answer on SO for details on how to do this.
Use Apache Ivy or Maven Ant Task in the existing build to produce and install a Maven artifact in your local repository. Use this artifact as a regular dependency in your Maven project (except that you'll have to declare its transitive dependencies manually). This is maybe the quicker and less intrusive approach if building both project separately is not a problem.
It looks like you choose option 3. I think it's a good choice for a quick win.
The solution I've used is the maven-ant tasks (http://maven.apache.org/ant-tasks/).
I added an install task onto the build.xml file, which installs the compiled .jar into the local repo.
While adding a full-fledged pom to the project would defintely be the best approach, this is a major chunk of work, and inflicts maven on the project (where the other users would prefer not to use it).
I think you probably need to bite the bullet and set up a POM for your OSS project tree. This is the painful part (as you would need to hunt down the details of specifying resources paths for various plugins involved depending on the OSS app type (i.e. web, etc.)). Good news is that this is a one time effort.
Once that is done, your main project can refer to the (wrapped) OSS project as a dependency. Here a (standard maven) multi-project structure would apply.
If OSS project has dependencies - create a POM with those dependencies (your project will use them as transitive dependencies) and install that artifact and pom in local repository. If OSS project hasn't any other dependencies is even simpler - the POM is generated automatically during installing.
For both cases use maven-install-plugin.
mvn install:install-file -Dfile=your-artifact-1.0.jar \
[-DpomFile=your-pom.xml] \
[-Dsources=src.jar] \
[-Djavadoc=apidocs.jar] \
[-DgroupId=org.some.group] \
[-DartifactId=your-artifact] \
[-Dversion=1.0] \
[-Dpackaging=jar] \
[-Dclassifier=sources] \
[-DgeneratePom=true] \
[-DcreateChecksum=true]

Maven: local development deploy vs bundling for distribution

Bear with me, I'm migrating from Ant to Maven2: I think I've hit one of those little things that was easy in Ant, but not so in Maven...
How do I handle the difference between a local deployment vs. creating an archive/bundle for distribution to another machine?
Let's assume my project's output is an EAR plus some additional config files. A developer that is actively working on the project will need to deploy and re-deploy frequently to his local app-server (say JBoss), while an Integration Engineer that is building for QA/production will need only to create the final archive assembly (tar/gz).
In Ant we had two targets for this: "dev-deploy" and "bundle". Both do a complete build, but differ in the final step: "dev-deploy" copies the EAR and config files to the respective local folders, while "bundle" just puts the EAR & config files in a tar.gz assembly.
How do you do this in Maven?
I've seen that the assembly plugin can create either archives (tar, gz, etc.) or exploded directories (from the same assembly descriptor). I can invoke either assembly:assembly or assembly:directory, but for the latter, how do I copy the final output to the local JBoss deployment folders? From a related post it seems that ad-hoc copying of files is not really what Maven is about, so an antrun copy is probably the most appropriate?
Finally, since the type of assembly may differ depending on who invokes it, it doesn't seem wise to bind assembly to the build lifecycle, not so? But this means that a developer will always need to invoke 'mvn package' followed by 'mvn assembly:directory' to rebuild and test a change. Conversely, an Integration Engineer will always need to run 'mvn package' followed by 'mvn assembly:assembly' to create the distributable archive. I was hoping for a one-command solution for each, or should I just script it?
In Ant we had two targets for this: "dev-deploy" and "bundle". Both do a complete build, but differ in the final step: "dev-deploy" copies the EAR and config files to the respective local folders, while "bundle" just puts the EAR & config files in a tar.gz assembly.
Not sure what you mean by respective local folders about "dev-deploy" but this sounds like what mvn pacakge is doing and "bundle" indeed sounds like a maven assembly.
I've seen that the assembly plugin can create either archives (tar, gz, etc.) or exploded directories (from the same assembly descriptor). I can invoke either assembly:assembly or assembly:directory, but for the latter, how do I copy the final output to the local JBoss deployment folders? From a related post it seems that ad-hoc copying of files is not really what Maven is about, so an antrun copy is probably the most appropriate?
I guess that we are talking about the Integration Engineer's tasks here. As you didn't explain what the "bundle" contains exactly, what the target application server is (my understanding is that you are using JBoss for QA/production too but, again, this is a guess), if this bundle has to be deployed automatically, it's hard to imagine all solutions and/or alternatives to antrun. But indeed, to copy/move/unzip/whatever the assembly, the maven antrun plugin is a candidate.
Finally, since the type of assembly may differ depending on who invokes it, it doesn't seem wise to bind assembly to the build lifecycle, not so? But this means that a developer will always need to invoke 'mvn package' followed by 'mvn assembly:directory' to rebuild and test a change. Conversely, an Integration Engineer will always need to run 'mvn package' followed by 'mvn assembly:assembly' to create the distributable archive. I was hoping for a one-command solution for each, or should I just script it?
My understanding was that the Integration Engineer was building the bundle. Why would a developer need the bundle? This is confusing... Anyway, I don't really need the details to think of an answer. You could actually declare the maven assembly plugin into specific build profiles, one for development and one for integration, and bind either the single or the directory-single mojos to the project's build lifecycle in each profile. This would allow to use only one command and avoid any scripting (really, don't go this way).

find dependencies in target/classes instead of local repository?

Summary: I'm looking for a way to instruct maven to search for dependencies in target/classes instead of jar in the local repository
Say I have 2 modules, A and B where A depends on B. Both are listed in a module S. Normally I need to run 'mvn install' in S. I'm looking for a way to run 'mvn compile' so that when A is compiled its classpath will contain ../B/target/classes instead of ~/.m2/repository/com/company/b/1.0/b-1.0.jar.
(my reason is so that i can have continous compilation without the need to go through packaing and installation, or, more exactly, use 'mvn scala:cc' on multiple modules)
I don't think that this is possible without horrible hacking, this is just not how maven works. Maven uses binary dependencies and needs a local repository to resolve them. So, the maven way to handle this is to launch a reactor build on all modules. Just in case, have a look at Maven Tips and Tricks: Advanced Reactor Options.
But, during development, can't you just import all your projects in your IDE and use "project references" (i.e. configure your projects to depend on source code instead of a JAR) like most Java developers are doing? This is the common approach to avoid having to install an artifact to "see" the modifications.
If this is not possible and if you really don't want to install artifacts into your local repository, then you'll have to move your code into a unique module.
i know this is annoying. which helped me here is definitely IDE support. eclipse and IntelliJ are clever to collect all dependencies once a maven-project import is done. even cross module dependencies are compiled live.