Conditional processing in Maven projects - maven

I have some configuration settings that are in the Maven project that I'd like to keep there for building into a newly set up system but not touched if the configuration setting already exists. One of the problems I had is that when I deleted the setting from the build, it also deleted the setting from the target server when I did a build.
What would good alternatives be?

A possible solution could be to move the particular set-up for the new systems in a Maven profile and activate the profile only based on either an environment variable or the existence/non-existence of a file.
For instance, from official documentation, you can activate the profile if a certain environment variable exists, not exists or exists with a certain value.
<profiles>
<profile>
<activation>
<property>
<name>environment</name>
<value>test</value>
</property>
</activation>
...
</profile>
</profiles>
Please also note that, as from official documentation:
Note: Environment variables like FOO are available as properties of the form env.FOO. Further note that environment variable names are normalized to all upper-case on Windows.
Alternatively, the profile can be activated on a certain file (existing or missing), as following:
<profiles>
<profile>
<activation>
<file>
<missing>path/to/missing/file</missing>
</file>
</activation>
...
</profile>
</profiles>
If your set-up cannot be applied to any of these two cases, you could (as an example) anyway adapt it to create an harmless file which would then deny any further set-up.
harmless file missing > profile activated > set-up performed
harmless file existing > profile not activated

Related

Is it possible to use a maven property to activate a profile based upon a file?

I would like to download the JACOB dlls when they're not in my local repository.
As a consequence, I have those two profiles
<profile>
<id>use-jacob-dll</id>
<activation>
<file>
<exists>${settings.localRepository}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</exists>
</file>
</activation>
<dependencies>
<dependency>
<groupId>${jacob.groupId}</groupId>
<artifactId>jacob</artifactId>
<type>dll</type>
<classifier>x64</classifier>
<version>${jacob.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>download-jacob-dll</id>
<activation>
<file>
<missing>${settings.localRepository}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</missing>
</file>
</activation>
But, even when download-jacob-dll has accomplished its goal, a call to mvn help:active-profiles indicates the following
The following profiles are active:
- tests-for-eclipse (source: com.capgemini.admdt:kpitv:1.2.4-SNAPSHOT)
- download-jacob-dll (source: com.capgemini.admdt:kpitv:1.2.4-SNAPSHOT)
I suspect it is due to the fact that I use the ${settings.localRepository} in my activation property.
Question: Is it the cause of the failure? And if so, how can I activate my profile only when dependency is missing ?
Is it possible to use a maven property to activate a profile based upon a file?
No, as stated by the Maven documentation on profiles
Supported variables are system properties like ${user.home} and environment variables like ${env.HOME}. Please note that properties and values defined in the POM itself are not available for interpolation here, e.g. the above example activator cannot use ${project.build.directory} but needs to hard-code the path target.
However, from the POM documentation we also get that
a given filename may activate the profile by the existence of a file, or if it is missing. NOTE: interpolation for this element is limited to ${basedir}, System properties and request properties.
Hence, indeed no Maven properties except ${basedir} are allowed.
And if so, how can I activate my profile only when dependency is missing?
By hardcoded path to the dependency or concerned file would be a solution, even though not portable like the solution you meant.
Alternatively you could use a request property as mentioned by the documentation above, thus need to configure the activation with a property which then must be passed from the command line (more portable but more fragile as well):
<activation>
<file>
<missing>${path}/com/hynnet/jacob/1.18/jacob-1.18-x64.dll</missing>
</file>
</activation>
Then invoke maven as following:
mvn clean install -Dpath=path_to_local_rep
The solution above could be reasonable in some contexts like Jenkins jobs.

Maven - Is it possible to build a project specifying multiple profiles simultaneously?

We are developing a Maven archetype for applications that only consume web services. This archetype offers three profiles, one for each environment (dev, pre, pro).
The point is that we would like to offer the possibility of having ORM dependencies included optionally (JPA, Hibernate) for those project that may require them in the future. We had though of creating an additional profile containing those dependencies.
When we build our project we use mvn package -Denvironment=dev. Is it possible to specify more than one profile such as: mvn package -Denvironment=dev,orm?
Yes, this is possible. But it seems you are confused about how profiles are activated in the first place.
The command
mvn package -Denvironment=dev
will not activate any profile without further configuration. In your case, it works because there must be a profile definition in your POM that is activated by the presence of the system property environment with a value of dev. The configuration you have would look like:
<profiles>
<profile>
<activation>
<property>
<name>environment</name>
<value>dev</value>
</property>
</activation>
</profile>
</profiles>
This is the magic that makes the profile activates when you pass the system property with -Denvironment. With that in mind, you can activate multiple profiles with the same idea: declare multiple <profile> element that are activated by the presence of a system property.
<profiles>
<profile>
<activation>
<property>
<name>myAwesomeProperty1</name>
<value>true</value>
</property>
</activation>
</profile>
<profile>
<activation>
<property>
<name>myAwesomeProperty2</name>
<value>true</value>
</property>
</activation>
</profile>
</profiles>
The above configuration would activate both profile if myAwesomeProperty1 and myAwesomeProperty2 is a system property with the value true.
In this particular case though, it seems that what you want is to activate a build depending on your environment so it could perhaps be a better idea to activate the profiles based on the -P command line switch, instead of a system property.
From Introduction to Build Profiles:
Profiles can be explicitly specified using the -P CLI option.
This option takes an argument that is a comma-delimited list of profile-ids to use. When this option is specified, the profile(s) specified in the option argument will be activated in addition to any profiles which are activated by their activation configuration or the <activeProfiles> section in settings.xml.
mvn groupId:artifactId:goal -P profile-1,profile-2
With this solution, you invoke Maven with multiple profile ids. That is to say, if you have in your configuration
<profiles>
<profile>
<id>profile-1</id>
<!-- rest of config -->
</profile>
<profile>
<id>profile-2</id>
<!-- rest of config -->
</profile>
</profiles>
The above invocation would activate both profile-1 and profile-2.

Can a Maven profile enable/disable another profile from its definition?

Given two profiles A and B, is it possible to specify something within profile A definition that would enable or disable profile B?
This is not possible to activate / deactivate a profile from another profile. Maven needs to know the list of active profiles before building the model.
There are a couple of work-arounds depending on your use-case:
Set one profile to activeByDefault: it will be automatically deactivated
when another profile is activated.
Use a custom property so that one profile is activated by the presence of the property and the other profile is deactivated by the presence of the property. Sample configuration would look like:
<profile>
<id>profileA</id>
<activation>
<property>
<name>somename</name>
</property>
</activation>
</profile>
<profile>
<id>profileB</id>
<activation>
<property>
<name>!somename</name>
</property>
</activation>
</profile>
Thus, if you invoke Maven with -Dsomename, profileA will be activated; otherwise profileB will be activated.

OS-Specific Maven Profile is always activated

I'm trying to define a profile that is activated only in case two conditions fit:
a special folder exists
the correct operating system
<profile>
<id>test</id>
<activation>
<file>
<exists>file</exists>
</file>
<os>
<family>windows/unix/etc...</family>
</os>
</activation>
</profile>
I tried to define it that way, but in case the operating system matches the profile is activated, even the folder does not exist. But I want to run some plugins in case the folder exists, in case a binary is required the operating system must match.
Thanks in advance..
According to the Maven JIRA, this is an open issue: http://jira.codehaus.org/browse/MNG-4565
The comments for the above-linked issue point to a Maven extension that provides the functionality you are looking for: https://github.com/johnjcool/and-activation-profile-selector

Is there a way to achieve reverse of maven profile activation by property?

I want to have a profile that triggers a certain plugin(say PMD) but I want to explicitly disable that plugin execution sometimes.
So I want to have a profile that is always active except when a property is defined.
Something like mvn -Dnopmd clean install, and the profile gets de-activated. Other than that the profile should always be active.
You can activate a profile when a property is not specfied like so:
<profile>
<id>someprofile</id>
<activation>
<property>
<name>!property.name</name>
</property>
</activation>
</profile>
This is also explained in the Maven documentation, Introduction to Build Profiles.

Resources