Унаследованные профили в Maven

У меня есть следующие профили в моем родительском помпе

<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>

Почему P1 активен в дочернем POM, а P2 - нет?

Каталог ${project.basedir}/src/main/whatever не существует в родительском проекте, но существует в дочернем.


person Adrian Ber    schedule 18.09.2013    source источник
comment
Существует ли каталог, указанный в условии активации для P2? Пожалуйста, указывайте полную информацию, когда задаете вопрос.   -  person Björn Pollex    schedule 18.09.2013
comment
Я отредактировал свой вопрос, чтобы ответить на ваш комментарий.   -  person Adrian Ber    schedule 18.09.2013
comment
@AdrianBer есть новости по этому поводу?   -  person linski    schedule 09.10.2013


Ответы (5)


Профиль P2 не активирован, так как путь под его тегом exists не разрешается в существующий путь, даже если каталог ${project.basedir}/src/main/whatever существует. Если вы перепишете свойство ${project.basedir} как ${basedir}, оно должно активировать профиль P2.

Это должно означать, что ${project.basedir} не разрешается в базовый каталог проекта, поскольку он должен. Однако help:effective-pom показывает, что это так. Я сообщил об этом (MNG-5516).

Также я думаю, что P1 не будет активен, если P2 активен.

Это правильно. Цитируя документацию для activeByDefault:

Этот профиль (P1 в этом примере) будет автоматически активен для всех сборок, если другой профиль в том же POM не будет активирован одним из ранее описанных методов. Все профили, которые активны по умолчанию, автоматически деактивируются, когда профиль в POM активируется в командной строке или через его конфигурацию активации.

Слово наследовать меня смутило, потому что «наследование профиля» работает в объединение проектов, но не в наследование проекта.

Чтобы было понятно, я смоделировал эту ситуацию. Пустой pom означает, что он пуст, за исключением стандартных тегов модели, группы, артефакта и версии.

Простой сценарий

Структура каталога:

simple
 \-pom.xml

содержание пом:

<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>

Если каталог dir отсутствует, mvn help:all-profiles выводит:

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

Если есть каталог dir, то mvn help:all-profiles выводит:

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

Наследование проекта

Структура каталога:

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

Дочерний pom пуст, а родительский pom имеет профили, как в простом сценарии. Независимо от существования каталога inheritance/child/dir запуск mvn help:all-profiles из каталога child выводит:

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

При запуске mvn help:effective-pom из каталога child показывает, что профили действительно не унаследованы. Он ведет себя как задокументировано:

Элементы в POM, которые объединяются, следующие:

  • зависимости
  • разработчики и участники
  • списки плагинов (включая отчеты)
  • выполнение плагина с соответствующими идентификаторами
  • конфигурация плагина
  • Ресурсы

Здесь не упоминаются профили.

Агрегация проекта

Структура каталога:

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

Модуль pom пуст, а агрегатор pom имеет профили, как в простом сценарии. Если нет каталога aggregation/module/dir, работающего под управлением mvn help:all-profiles из каталога module, выводится:

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

Если есть каталог aggregation/module/dir, работающий под управлением mvn help:all-profiles из каталога module, выводятся:

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

При запуске mvn help:effective-pom из каталога module показывает, что профили унаследованы. Это не явно задокументировано:

Наследование проекта

Если у вас есть несколько проектов Maven, и все они имеют схожие конфигурации, вы можете реорганизовать свои проекты, вытащив эти похожие конфигурации и создав родительский проект. Таким образом, все, что вам нужно сделать, это позволить вашим проектам Maven наследовать этот родительский проект, и эти конфигурации будут применяться ко всем из них.

Примечания:

  • Это не относится к профилям, как было показано.
  • Запуск сборки maven из каталога inheritance запустит только родительскую сборку.

Агрегация проектов

И если у вас есть группа проектов, которые строятся или обрабатываются вместе, вы можете создать родительский проект, и этот родительский проект объявит эти проекты в качестве своих модулей. Таким образом, вам нужно будет только построить родителя, а остальное последует.

Примечания:

  • Запуск сборки maven из каталога aggregation запустит сборку каждого модуля и агрегатора (фактический порядок определяется maven на основе разных критериев).

Вывод

Профили могут быть определены глобально, для каждого пользователя или для каждого проекта. Поскольку агрегированные проекты строятся вместе (в одной сборке), необходимо выполнить какое-то разрешение профиля для расчета активных. Итак, это запутанная часть:

  • Когда проекты наследуются, профили не наследуются от родительского pom к дочернему pom.
  • когда проекты объединяются, профили наследуются от агрегатора pom к модулю pom.

Это было протестировано с использованием Maven 3.1.0. и 3.0.5.

person linski    schedule 19.09.2013
comment
-1 Этот пост вводит в заблуждение. Профили на самом деле наследуются от родительского pom к дочернему pom. Смотрите мой ответ. - person Noremac; 31.12.2013
comment
Пост не вводит в заблуждение. Я протестировал профиль, унаследованный от maven 3.3.9. Если родительский pom объявляет дочерний модуль (агрегацию), профиль отображается в дочернем модуле. Если родительский pom не объявляет дочерний модуль (наследование), профиль не виден. - person Paulo Merson; 16.03.2017
comment
@PauloMerson, что, если у вас есть и то, и другое (например, наследование проекта и агрегация проекта)? - person mre; 30.06.2017

Просто чтобы уточнить это, профили Maven на самом деле наследуются. Ссылку на другой вопрос SO см. в разделе Наследование профилей Maven. Я успешно унаследовал профили в своем проекте, и дополнительная работа не требуется.

Что касается исходного вопроса, у вас есть переменная, определенная в элементе exists. Согласно документации:

Начиная с Maven 2.0.9, теги и могут быть интерполированы. Поддерживаемые переменные — это системные свойства, такие как ${user.home}, и переменные среды, такие как ${env.HOME}. Обратите внимание, что свойства и значения, определенные в самой POM, здесь недоступны для интерполяции, например. приведенный выше пример активатора не может использовать ${project.build.directory}, но должен жестко закодировать целевой путь.

Итак, что я получаю из этого, так это то, что ${project.basedir} нельзя использовать и он не будет работать. Однако, если вы определили его как переменную среды, он будет работать.

Одно предостережение, которое я обнаружил, заключается в том, что в родительском pom <plugin-management> следует использовать для настройки плагинов. Однако внутри профилей я обнаружил, что <plugin-management> нельзя использовать, чтобы конфигурация, специфичная для профиля, работала.

person Noremac    schedule 30.12.2013
comment
Вы правы насчет наследования профилей, это работает из коробки, как и ожидалось. Если вы определяете плагин в профиле в profiles/profile/build/plugins и его конфигурацию в profiles/profile/build/pluginManagement/plugins, плагины применяются, когда профиль активен, как и ожидалось, поэтому я не думаю, что Последнее утверждение о том, что секция управления плагинами не работает в профилях, верно. - person Richard; 02.10.2018
comment
На самом деле я обнаружил еще одну проблему, над которой я работал, но все еще не мог правильно решить: иногда указание чего-то в конфигурации плагина не распространяется должным образом на каждое выполнение, определенное в этом плагине, что означает, что я должен скопировать, например. имя пользователя, пароль и jdbc-строку (например, sql-maven-plugin) в конфигурацию каждого выполнения. Это выглядит как незначительная проблема с XML-слиянием, но это не слишком большая проблема, поэтому я не делал никаких проблем в этом отношении. - person Igor; 14.05.2019

Проблема не в наследовании, а в интерполяции (т. е. в том, какие значения поддерживаются для ${...}): активация профиля на основе файлов поддерживает только ограниченную интерполяцию: см. http://maven.apache.org/pom.html#Activation

Так что ${project.basedir} не поддерживается, а только ${basedir} (и системные свойства).

Для получения более подробной информации вы можете ознакомиться с алгоритмом построения модели: http://maven.apache.org/ref/3.2.1/maven-model-builder/

Полная интерполяция модели происходит после активации профиля: поэтому, даже если ваш эффективный pom показывает интерполированное значение для ${project.basedir}, значение не рассчитывается при активации профиля.

В Maven 3.2.2 есть несколько улучшений по этому поводу: документация в http://jira.codehaus.org/browse/MNG-5590, предупреждение во время выполнения в http://jira.codehaus.org/browse/MNG-5608 и более эффективный результат pom http://jira.codehaus.org/browse/MNG-5612

person hboutemy    schedule 23.03.2014

Как правило, профили Maven не наследуются (см. http://jira.codehaus.org/browse/MNG-5127 для обсуждения и ссылок на посты в блоге, которые могут быть полезны). У меня был успех, делая что-то вроде этого:

<!-- 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>

Также я думаю, что P1 не будет активен, если P2 активен. Это потому, что <activeByDefault> верно для P1. На мой взгляд, название элемента немного вводит в заблуждение. «Активен по умолчанию» подразумевает «всегда активен», когда на самом деле это означает «активен, только если никакой другой профиль в этом POM не активен».

Вышеупомянутое обнаружено с помощью Maven 3.0.x.

person user944849    schedule 18.09.2013
comment
Разве упомянутая проблема JIRA не говорит: Активация профиля на основе файла действительно наследуется? По моему опыту, активированный файл (или папка) профиль в родительском элементе активируется, если файл (или папка) доступен относительно дочернего проекта (т.е. ${basedir} относится к дочернему проекту). - person Sander Verhagen; 19.09.2013
comment
Хорошо, если свойство было удалено из ‹exists›, тогда оно должно быть унаследовано для этого сообщения. Я использовал описанную выше технику, чтобы активировать некоторые свойства, поэтому теперь я просто применяю ее каждый раз, когда хочу наследовать профиль. - person user944849; 19.09.2013

Удалите P2 из второго профиля с файловой активацией.

<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>
person MarkBarry    schedule 14.11.2014