Inherited profiles in Maven
Asked Answered
J

5

11

I have the following profiles in my parent pom

<profile>
    <id>P1</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
</profile>

<profile>
    <id>P2</id>
    <activation>
        <file>
            <exists>${project.basedir}/src/main/whatever</exists>
        </file>
    </activation>
</profile>

Why P1 is active in child POM and P2 isn't?

The directory ${project.basedir}/src/main/whatever, does not exist in the parent project, but exists in the child one.

Jehial answered 18/9, 2013 at 9:38 Comment(3)
Does the directory referenced in the activation condition for P2 exist? Please provide complete information when asking a question.Dilantin
I edited my question to answer to your comment.Jehial
@AdrianBer is there any update on the matter?Unmannerly
U
28

Profile P2 is not activated because the path under its exists tag does not resolve to an existing path even though the directory ${project.basedir}/src/main/whatever exists. If you rewrite the property ${project.basedir} as ${basedir}, it should activate the P2 profile.

That should mean that the ${project.basedir} does not resolve to the project base directory as it should. The help:effective-pom shows that it does, though. I have reported this (MNG-5516).

Also I think that P1 will not be active if P2 is.

That is correct. Quoting the documentation for activeByDefault:

This profile (P1 in this example) will automatically be active for all builds unless another profile in the same POM is activated using one of the previously described methods. All profiles that are active by default are automatically deactivated when a profile in the POM is activated on the command line or through its activation config.

The word inherit got me confused, because the "profile inheritance" works in project aggregation but not in project inheritance.

To make things clear, I simulated this situation. Empty pom means that it is empty except for the standard model, group, artifact and version tags.

###Simple scenario

Directory structure:

simple
 \-pom.xml

pom content:

<profiles>
    <profile>
        <id>P1</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <id>P2</id>
        <activation>
            <file>
                <exists>${basedir}/dir/</exists>
            </file>
        </activation>
    </profile>
</profiles>

If there is no dir directory mvn help:all-profiles outputs:

Profile Id: P1 (Active: true , Source: pom)
Profile Id: P2 (Active: false , Source: pom)

If there is dir directory mvn help:all-profiles outputs:

Profile Id: P2 (Active: true , Source: pom)
Profile Id: P1 (Active: false , Source: pom)

###Project inheritance

Directory structure:

inheritance
 |--child
 |  \-pom.xml         // child pom
 \-pom.xml           // parent pom

Child pom is empty while parent pom has the profiles as in the simple scenario. Regardless of the existence of the inheritance/child/dir directory running mvn help:all-profiles from child directory outputs:

Profile Id: P1 (Active: false , Source: pom)
Profile Id: P2 (Active: false , Source: pom)

When running mvn help:effective-pom from child directory it shows that the profiles are indeed not inherited. It behaves as documented:

Elements in the POM that are merged are the following:

  • dependencies
  • developers and contributors
  • plugin lists (including reports)
  • plugin executions with matching ids
  • plugin configuration
  • resources

No profiles are mentioned here.

###Project aggregation

Directory structure:

aggregation
 |--module
 |  \-pom.xml         // module pom
 \-pom.xml           // aggregator pom

Module pom is empty while aggregator pom has the profiles as in the simple scenario. If there is no aggregation/module/dir directory running mvn help:all-profiles from module directory outputs:

Profile Id: P1 (Active: true , Source: pom)
Profile Id: P2 (Active: false , Source: pom)

If there is aggregation/module/dir directory running mvn help:all-profiles from module directory outputs:

Profile Id: P2 (Active: true , Source: pom)
Profile Id: P1 (Active: false , Source: pom)

When running mvn help:effective-pom from module directory it shows that the profiles are inherited. This is not explicitly documented:

Project inheritance

If you have several Maven projects, and they all have similar configurations, you can refactor your projects by pulling out those similar configurations and making a parent project. Thus, all you have to do is to let your Maven projects inherit that parent project, and those configurations would then be applied to all of them.

Notes:

  • That does not apply to profiles, as it has been shown.
  • Runnnig a maven build from inheritance directory will run only parent build.

Project aggregation

And if you have a group of projects that are built or processed together, you can create a parent project and have that parent project declare those projects as its modules. By doing so, you'd only have to build the parent and the rest will follow.

Notes:

  • Runnnig a maven build from aggregation directory will run the build of each module and the aggregator (the actual order is determined by maven based on different criteria).

###Conclusion

Profiles can be defined globally, per user or per project. Since the aggregated projects are built together (in the same build) some sort of profile resolution must be run to calculate the active ones. So this is the confusing part:

  • When projects are inherited profiles are not inherited from parent pom to child pom.
  • when projects are aggregated profiles are inherited from aggregator pom to module pom.

This was tested this using Maven 3.1.0. and 3.0.5.

Unmannerly answered 19/9, 2013 at 16:4 Comment(3)
-1 This post is misleading. Profiles are in fact inherited from a parent pom to child pom. See my answer.Bristol
The post is not misleading. I tested the profile inheritanced with maven 3.3.9. If the parent pom declares the child module (aggregation), the profile is visible in the child module. If the parent pom does not declare de child module (inheritance), the profile is not visible.Homeomorphism
@PauloMerson, What if you have both (i.e. Project Inheritance and Project Aggregation)?Darrelldarrelle
B
11

Just to clarify on this, Maven Profiles are in fact inherited. For a reference to another SO question see: Inheriting Maven profiles. I have successfully inherited profiles in my project and no additional work is needed.

As for the original question, you have a variable defined in the exists element. According to the documentation:

As of Maven 2.0.9, the tags and could be interpolated. 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.

So, what I get from that is that ${project.basedir} cannot be used and will not work. If however you have it defined as an environment variable, it will work.

One caveat that I found is that in the parent pom <plugin-management> should be used to configure the plugins. However, for within the profiles I find that <plugin-management> must not be used in order for the profile-specific configuration to work.

Bristol answered 30/12, 2013 at 21:1 Comment(2)
You are right about profiles being inherited, it works out of the box as expected. If you define a plugin in a profile under profiles/profile/build/plugins and its config under profiles/profile/build/pluginManagement/plugins, plugins are applied when the profile is active as expected as well - so I don't think the last statement about plugin-management section not working in profiles is correct.Gold
Actually I had found another issue, that I worked around, but still could not properly solve: sometimes specifying something in the plugin-configuration does not carry over properly to each execution defined within this plugin, which means that I have to copy e.g. username, password and jdbc-string (in e.g. sql-maven-plugin) into the configuration of each execution. This looks like some minor XML-merge issue, but is not too much of a problem - which is why I made no issue in that regard.Tallent
B
7

The problem is not with inheritance but with interpolation (i.e. which values are supported for ${...}): file-based profile activation only supports limited interpolation: see http://maven.apache.org/pom.html#Activation

So ${project.basedir} isn't supported but only ${basedir} (and system properties).

For more details, you can have a look at the model building algorithm: http://maven.apache.org/ref/3.2.1/maven-model-builder/

Full model interpolation happens after profile activation: so even if your effective pom shows interpolated value for ${project.basedir}, the value isn't calculated when profile activation happens.

In Maven 3.2.2, there are multiple enhancements regarding this: documentation in http://jira.codehaus.org/browse/MNG-5590, warning at runtime in http://jira.codehaus.org/browse/MNG-5608 and better effective pom result http://jira.codehaus.org/browse/MNG-5612

Boor answered 23/3, 2014 at 15:55 Comment(0)
T
1

In general, Maven profiles are not inherited (see http://jira.codehaus.org/browse/MNG-5127 for a discussion and links to blog posts that might be useful). I've had success doing something like this:

<!-- Parent -->
<profile>
    <id>P2</id>
    <activation>
        <file>
            <exists>${project.basedir}/src/main/whatever</exists>
        </file>
    </activation>
    <!-- all the things you want to define for the child POMs -->
</profile>

<!-- Child -->
<!-- Include only the activation block, which must match parent's exactly -->
<!-- Whatever is in the parent will be inherited -->
<profile>
    <id>P2</id>
    <activation>
        <file>
            <exists>${project.basedir}/src/main/whatever</exists>
        </file>
    </activation>
</profile>

Also I think that P1 will not be active if P2 is. This is because <activeByDefault> is true for P1. The element name is a little misleading in my opinion. "Active by default" implies "always active" when it really means "active only if no other profile in this POM is active."

The above discovered using Maven 3.0.x.

Tacheometer answered 18/9, 2013 at 14:6 Comment(2)
Doesn't the referenced JIRA issue not say: "File-based profile activation is actually inherited"? In my experience a file (or folder) activated profile in the parent is activated if the file (or folder) is available, relative to the child project (i.e. ${basedir} is relative to the child project).Nihil
Good point, if the property was removed from the <exists> then it should be inherited per that post. I've used the technique above to get some of the property activation to work, so now I just apply it any time I want to inherit a profile.Tacheometer
P
0

Remove the P2 from the second profile that has the file based activation.

<profiles>
    <profile>
        <id>P1</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <id>P2</id>
        <activation>
            <file>
                <exists>${basedir}/dir/</exists>
            </file>
        </activation>
    </profile>
</profiles>
Postrider answered 14/11, 2014 at 6:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.