Maven profile activation with multiple conditions - maven-2

I'm working on getting the rpm-maven plugin setup in a project. In our staging and production environments, the build occurs on Red Hat boxes, but we have several Windows boxes that are used for development and testing so I wanted the RPM build process to be part of a profile that is only active on a box that has rpmbuild installed.
This was my first attempt at an activation condition:
<activation>
<os>
<family>unix</family>
</os>
<file>
<exists>/usr/bin/rpmbuild</exists>
</file>
</activation>
My initial testing only involved building on a Windows box and building on a CentOS box, and both gave me the results I expected. Later, the build broke on a Linux machine that didn't have rpmbuild available. It looks like having two conditions like this isn't supported. Is this the case? I realize I can probably just get rid of the <os/> element and get the results I want, but for future reference is there a better way to create profiles with multiple activation conditions?

Maven <activation> block is a list of OR -- the profile will be activated as soon as the first criteria is met. So, it is less likely that your problem has a solution at least until this bug-report gets fixed https://issues.apache.org/jira/browse/MNG-4565
Update:
it's fixed in 3.2.2 now – sfussenegger (via comment)

And worst you can mix condition of different type for example file, jdk and property as described here http://www.sonatype.com/books/mvnref-book/reference/profiles-sect-activation.html, but you can't even put two condition of same type, for example two properties
<activation>
<property>
<name>integrationTest</name>
</property>
<property>
<name>packaging</name>
<value>swf</value>
</property>
</activation>
This won't work as only one <property> tag will be allowed.
Associated JIRA : https://issues.apache.org/jira/browse/MNG-3328
And the bug described above is still open... 5 years it's just a shame !

Just fixed by me :)
Starting from 3.2.2 it will work as expected: multiple conditions will be ANDed
Reference - https://github.com/apache/maven/commits/master, search by MNG-4565
Commit URL - https://github.com/apache/maven/commit/c6529932f9e3efdfc86ed73f59a307a8f8b6ea5f

I think this is what these Maven extensions do:
Maven EL Profile Activator Extension
This one is pretty simple, have a look at the source
Maven Profile Activation Extension
This one has more options for the actual activation expression, including Scala.
However, since it's an extension (not a plugin), every project using it will have to register the extension. And there's a risk that the project author will abandon it and it won't work in future maven versions.

Related

CDI and JANDEX and deployment enhancement approach - no speed difference detected

I am opening this thread as I was requested to do so, in a reply to comment/question i added here:
Disable scanning of CDI beans in WAR
The question is the following.
Is there any specific additional step that one needs to take besides adding jandex to his build pom to get the feature enabled?
I notice no deployment speed difference when using jandex on Wildfly 10.1.0.Final and Weblogic 12.2.1.2 deployments. If anything, the deployment tends to be about 1 second slower.
Steps taken:
1. Visit https://github.com/wildfly/jandex-maven-plugin
Enrich a multi-module pom with the plugin
<plugin>
<groupId>org.jboss.jandex</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>1.0.5</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
<!-- phase is 'process-classes by default' -->
<configuration>
<!-- Nothing needed here for simple cases -->
</configuration>
</execution>
</executions>
</plugin>
Notice that all .jar files have a size relatively larger due to the contained Jandex.idx that gets written to the META-INF/
Deploy the WAR application via wildfly/weblogic console
No difference at all in deployment time.
And on this point, believe me, the application is not light-weight on the number of CDI beans it holds.
This is something being addressed, but as a short-time solution I would like to find a quickfix to accelerate the deployment time and was hoping Jandex to have some impact.
Instead it seems to make 0 difference, if anything the deployment with jandex always seemed to take one to two seconds extra.
Perhaps additional information that might be relevant.
Both in wildfly and in weblogic, there is a tunning that can be done to tell the newer versions of WELD to not scan all deployed .jar files.
We use the setting that tells weld to only consider jar files with the beans.xml file within them.
And these jar files have bean-discover="all" - while CDI recommends that one uses the "annoted" approach to speed up analysis time and memmory foot print (but that would require a bigger refactoring).
See http://weld.cdi-spec.org/news/2016/10/25/tip3-performance/
So in short:
Is there something more that needs to be done to tell a container to consider the jandex index.
Or is it simply that Weld is already so fast analyzing the deployed classes, that pre-building the index makes virtually no difference except to add up to the deployment a few MBytes?
I would assume not because Jandex is still mentioned as weld tip for deployment speed improvement, so I am tempted to think I am missing some piece of configuration.
Many thanks for any help on this front.
You are right - this won't be faster. It would be (most likely) in SE and Servlet but not necessarily in EE server.
Weld SPI offers a service interface to integrators (such as WildFly and WebLogic) and they may or may not choose to use it and feed Weld with class info (from Jandex for instance). Now, I don't know about WebLogic, but I guess they don't use Jandex at all (it's WFLY sub-project after all). But when we talk WildFly, they do use Jandex, but they create their own Jandex index "on-the-fly" during deployment which they then use instead of the pre-prepared one you might have had there. That explains the additional second of something you see.
On the other hand, in SE/Servlet environment, Weld is an "integrator" for itself and can (and does) make sure that Jandex will be used.

How might maven's buildNumber metadata become inconsistent across multiple build agents?

We recently added a second build machine to our build environment and began experiencing very odd occasional build failures.
I have two separate Maven build machines, A and B, each running Maven 2.2.1 and communicating to a shared Nexus 1.5.0 repository manager. My problem is that builds on B will occasionally fail because it refuses to download a newer version of a common dependency 'acme-1.0.0-SNAPSHOT' previously built by A and uploaded to Nexus.
Looking inside the local repositories on both machines I noticed some oddities in the repository metadata.
Machine A's acme\1.0.0-SNAPSHOT\maven-metadata-nexus.xml:
<metadata>
<groupId>acme</groupId>
<artifactId>acme</artifactId>
<version>1.0.0-SNAPSHOT</version>
<versioning>
<snapshot>
<buildNumber>1</buildNumber>
</snapshot>
<lastUpdated>20100525173546</lastUpdated>
</versioning>
</metadata>
Machine B's acme\1.0.0-SNAPSHOT\maven-metadata-nexus.xml:
<metadata>
<groupId>acme</groupId>
<artifactId>acme</artifactId>
<version>1.0.0-SNAPSHOT</version>
<versioning>
<snapshot>
<buildNumber>2</buildNumber>
</snapshot>
<lastUpdated>20100519232317</lastUpdated>
</versioning>
</metadata>
In Nexus's acme/1.0.0-SNAPSHOT/maven-metadata.xml:
<metadata>
<groupId>acme</groupId>
<artifactId>acme</artifactId>
<version>1.0.0-SNAPSHOT</version>
<versioning />
</metadata>
If I'm interpreting the metadata files correctly (documentation online is scant), it appears machine B believes it has a newer version of the acme dependency (based on buildNumber) despite the fact that machine A last built it 6 days after machine B did (based on timestamp). Nexus also appears to be unaware of a universally correct buildNumber.
How could this situation possibly arise? What could I do to prevent my builds from failing due to inconsistent metadata? Have you experienced anything similar?
Important notes:
Both build machines have settings.xml files where the updatePolicy is "always".
Nexus does indeed have the newer version of acme that was built by A. B simply refuses to download it.
A and B are the only machines uploading to Nexus.
Both servers share the same system time.
All processes involved have write privileges to the metadata files so that they can be updated as necessary.
I was unable to find any open Maven or Nexus issues describing this behaviour.
Our CI server (Atlassian Bamboo) prevents builds of the same artifact from happening concurrently, so some race condition while uploading to Nexus is rather unlikely.
It looks like you posted the wrong maven-metadata from Nexus, this looks like the one in the acme folder rather than the acme/1.0-SNAPSHOT folder. (it would have the build number and timestamp in there).
Anyway, have you tried adding -U to the maven build commands? It's possible that you've stumbled upon some maven bug respecting the always setting, but I'm sure -U works.
It took me a while, but I tracked down the underlying issue to maven bug MNG-4142.
Here's what happened:
My acme-1.0-SNAPSHOT (build 1) was installed on A and uploaded to Nexus. The project was next built on B where the newly built acme-1.0-SNAPSHOT (build 2) was installed and uploaded to Nexus, overriding build 1.
Then, when a build happened on the A machine that had acme-1.0-SNAPSHOT as a dependency, MNG-4142 kicked in. The repository metadata contained "true" which prevented A from downloading the more recent build 2 of acme-1.0-SNAPSHOT, and so maven built my project against the older build 1 which caused build failures. This was still the case even when -U was used.
As I mentioned on the issue, I'm quite surprised at this behaviour and struggle to think of how other distributed build environments work in the presence of this bug. We currently have some cron jobs that frequently change the "localCopy" metadata to false in order to get what I believe should be the default, and correct, behaviour.

Maven - activate child profile based on property

Scenario:
Given
Parent POM which defines a profile and a child (as module)
Child project(s) that will be using the profile by referring to the parent POM.
The intent is to skip profile execution in the parent and execute it in the child only
Profile has activation section <activation><property><name>foo</name></property><activation>
Since parent does not define foo property - the profile is inactive and will not be executed for the parent build
Now, I'm defining <properties><foo>true</foo></properties> in the child with hope that the property will be picked up when child build is executed and profile will be activated. No such luck. Profile is never activated, which tells me that property is never set.
Just to note: mvn package -Dfoo=true activates profile in both parent and child
Am I trying to do the impossible or just doing it wrong?
P.S. Hmmm - even if I define property in the parent, the profile is not triggered. What gives?
To expand on #rich-seller's answer, and #Bostone's self-answer, it seems to be impossible to have a setup where the parent POM defines a few profiles as alternatives, and child POMs select one of these profiles by default, while allowing you to override the choice for a child temporarily (i.e. on the CLI). Consider a parent POM for projects which use some framework and an associated plugin, both of whose versions we can assume are defined by properties:
<profiles>
<profile>
<id>newest</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<framework.version>2.0</framework.version>
<plugin.version>2.0</plugin.version>
</properties>
</profile>
<profile>
<id>older</id>
<activation>
<property>
<name>older.framework</name>
<value>true</value>
</property>
</activation>
<properties>
<framework.version>1.1</framework.version>
<plugin.version>1.1</plugin.version>
</properties>
</profile>
</profiles>
Now a child inheriting from this parent POM by default will use 2.0 as you would expect, and -Polder or -Dolder.framework=true will work to try building it with the older framework (e.g. to test compatibility). However you cannot write in the child POM
<properties>
<older.framework>true</older.framework>
</properties>
and have the older profile be activated automatically. You could use file-based activation to make this module build against 1.1 if newest were not active by default, but then it is not easy to temporarily run it against 2.0: as far as I know both older and newest profiles would be active if you passed -Pnewest, so you need to explicitly disable other profiles which is unreasonable if you have a dozen of them. So there is just no solution except to copy the profile information to the child POM:
<properties>
<framework.version>1.1</framework.version>
<plugin.version>1.1</plugin.version>
</properties>
at which point -Pnewest will not work to override these properties, so you need to use -Dframework.version=2.0 -Dplugin.version=2.0.
In other words, the profiles are only useful if all the child modules can use the same profile (here newest) by default. If some of them are normally built with 1.1 and some with 2.0, the profiles are useless.
Seems like this is a use case for a Maven core enhancement, or perhaps a Maven 3 build extension. http://docs.codehaus.org/display/MAVEN/Custom+Profile+Activators and https://github.com/maoo/maven-tiles come to mind.
The profile can only be activated by properties passed from the command line. This is because properties in the POM can only be processed once the POM has been parsed, at which point it is too late to resolve the profile activation.
You're in a bit of a catch-22 with this approach unless you are able to pass the property from the command line, specify profile activation in your settings.xml (generally not a great idea), or use the workaround in my previous answer to use the presence of a marker file.
One final alternative if you're on Maven 2.1.0+ is to deactivate the profile via the command line for the parent POM only, this is still obviously not ideal.
You can deactivate a profile with either the character '!' or '-' like this:
mvn install -P !profile-1,!profile-2
To directly answer my own question: in multi-module build all properties are set before build is run so it is impossible to activate/deactivate profile in one of the modules during the build based on setting the propety in the child POM. However if you are looking for way of doing it by using other means please read this comment

Activate different Maven profiles depending on current module?

We have a multi module build with modules using different technologies, like Java and Flex. Is it somehow possible to activate different profiles based on the module that is compiled currently?
I tried it with an activation like
<profile>
<id>flex</id>
<activation>
<file>
<exists>${basedir}/src/main/flex</exists>
</file>
</activation>
...
</profile
But it didn't work, although the use of ${basedir} is documented in the Maven documentation (this is a bug in Maven). Is there a different possibility to have different activations based on the current module? Or does Maven only allow to activate a profile for all modules or not at all?
After some more research I finally came to the conclusion that this is not possible for two reasons in the current Maven version (2.1.0):
Maven profiles are not inherited, so you can't define a profile in a parent POM and activate that in a child POM.
I haven't found a possibility to activate a profile from a POM itself. The activation does not work with ${basedir} and the property activation response only to system settings, which are globally specified through the -D option.
For those like myself reading this question looking for answers, this use case now works in Maven 3.
There is was a bug affecting this feature in early versions of 3 (see http://jira.codehaus.org/browse/MNG-2363) but it works for me correctly using Maven 3.0.4.
In 2.2.1, profiles are inherited but the ${basedir} issue is still there. I'm in the same boat - I need to activate a profile based on the existence of a file in a given project. My child builds run individually just fine (inherited profile activated by local file existance), but if I run the build from the top parent, they fail because the file isn't found.
With regard to file-based activation, you can try removing ${basedir}. We use it like this:
<activation>
<file>
<missing>target/jboss/conf/jboss-service.xml</missing>
</file>
</activation>
I dont know if this helps, but I solved a similar problem with the following approach:
I created and described the profile in the parent POM, which has activeByDefault=false. The PluginManagement-Section then contains the configurations for different plugins.
The children can reuse this profile, and set activeByDefault=true
This makes the profile active, but still none of the plugins are activated.
But fortunately the described plugin configurations are available. You can reuse them in children by defining them in the Plugins-Section. You just provide the group- and the artifactID, and set inherited=true for each plugin you want to reuse in the children.
I hope that helps. Sorry for not including any code snippets, but I hope even so the soutions is understandable.
You can set a property in each module that you want to use the profile, and then use "property" activation in your profiles.

Creating documentation with maven

I'm just in the middle of revisiting maven. Our team had a bad experience when we last looked at this, as it was during the period when maven was rearchitecting from 1.x to 2.x, so a lot of the dependencies we needed hadn't been moved across to the new repositories. However, I have the time to reconsider now.
I am interested in using maven and either LaTeX or DocBook for creating documentation, and I was wondering if anyone had any experiences to share, project/module structure, good plugins to use, etc...
Many thanks :-)
Edit:
Just to clarify, I was looking to write a technical article/book, and my desired artifact would probably be a PDF.
DocBook is one of the many supported inputs to Doxia, the engine used to generate docs by maven. Refer here: http://maven.apache.org/doxia/modules/index.html
In fact, the Doxia site answers your exact question: http://maven.apache.org/doxia/book/index.html
You can easily create a site (that contains documentation) with Maven using the mvn site command (i.e. using the plugin site).
This plugin creates technical reports (such as Javadoc, Unit tests reports, code coverage...) but can be also used to create a "real site".
You have more details about that in this page.
Basically, you write your page using APT (Almost Plain Text which is quite simple to understand), or a XML-based format, Xdoc.
2 years ago, I create a complete user guide for one application I developed, using the XDoc format and the Site Maven plugin. Globally, it was quite easy to create!
I hope this will help you!
I've been using with success the Maven plugin Docbkx. You should give it a try
Docbkx
You should definitely take a look at the Maven Docbkx Plugin. It probably fits your needs. Doxia's support of DocBook is -uhm- suboptimal. In fact, last time I tried it, it generated something new that - as far as I could tell - wasn't DocBook.
The Maven Docbkx Plugin that I'm referring to supports all the customizations of the world (through plugin parameters, or XSLT overrides, if you're into that) + it features some mechanisms to integrate it with the Maven build. (Such as processing instructions for including Maven pom properties into your documents.)
Note that the ambition is to have a plugin that prevents you from having to manually put together a processing chain yourselves. So this plugin will both do the transformation to FO, and transforming that to PDF.
I recently implemented the project documentation for my maven multi-module project using docbook and the docbkx plugin for maven. I now have it automatically generating html and pdf files every time I build the project site. I think docbkx really rocks, so I would suggest you use that.
Its true -you can create a very nice site just using the maven site and doxia plugins. In fact I'm using those two to generate my project site, But doxia support for docbook is very limited and doesn't let you modularize documentation, including parts of documents in a main document, for instance. So for the big reference-manuals I'm using docbkx.
If you want to take a peek, my project is here. You can actually download the source and see the nitty gritty of it. And, of course, if you have any question regarding this setup, i'll be more than glad to help.
Cheers
Carlos
Although the question is quite old I want to give an update on this. If you want to use LaTeX for your documentation you should use a maven plugin to generate the documentation. There are a couple of maven-plugins doing this but a lot of them are not maintained anymore.
There is a new maven-plugin which requires none or less configuration to get it working and the generated PDF (or PS or DVI) can be published as artifact.
Have a look at: mathan-latex-maven-plugin
There is AFAIK no official or semi-official plugin that will process LaTeX or DocBook, but what you could do (besides using the aforementioned site plugin) is to configure the exec plugin to process your LaTeX/DocBook sources during the site lifecycle, i.e. at the same time that the project's website is built.
E.g., something like
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>latex</id>
<goals>
<goal>exec</goal>
</goals>
<phase>site</phase>
<configuration>
...
</configuration>
</execution>
</executions>
</plugin>