Свойство Maven2, указывающее родительский каталог

107

У меня есть проект с несколькими модулями, например этот:

main-project/
    module1/
    module2/
        sub-module1/
        sub-module2/
        sub-module3/
        ...
    module3/
    module4/
    ...

Мне нужно определить набор свойств (которые зависят от среды, в которой я хочу выпустить свой проект) в Maven2. Не буду использовать, так <properties>как свойств много ... Поэтому я использую плагин Properties Maven2 .

Файлы свойств находятся в main-project/каталоге. Как я могу установить правильный каталог в основном pom.xml, чтобы указать детям, где найти файл свойств?

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <file>???/env_${env}.properties</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

Если я установил только <file>env_${env}.properties</file>, то когда Maven2 компилирует первый модуль, он не найдет main-project/env_dev.propertiesфайл. Если я установлю <file>../env_${env}.properties</file>, то на родительском уровне или на любом уровне подмодуля возникнет ошибка ...

Ромен Линсолас
источник
1
Просто используйте${maven.multiModuleProjectDirectory}
qoomon

Ответы:

165

Попробуйте установить свойство в каждом pom, чтобы найти главный каталог проекта.

В родительском:

<properties>
    <main.basedir>${project.basedir}</main.basedir>
</properties>

У детей:

<properties>
    <main.basedir>${project.parent.basedir}</main.basedir>
</properties>

У внуков:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>
Глина
источник
19
Были ли удалены эти предварительно установленные свойства? ${parent.basedir}больше ничего не разбирает в 3.0.4 ...
matt5784
7
Да, это не работает. $ {project.parent.basedir} возвращает значение null.
Джаред
22
У меня был успех, ${project.basedir}/..но это действительно работает только в многомодульных проектах, которые находятся в строгой иерархии каталогов.
Джонатан
90
Вздох. Невероятно, но Maven так усложняет задачу.
Stefan Haberl
5
Как и Джонатан выше, я должен использовать относительные пути, но считаю, что лучше всего использовать такую file.separatorпеременную<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired
29

По крайней мере, в текущей версии maven (3.6.0) вы можете использовать ${maven.multiModuleProjectDirectory}

Qoomon
источник
2
Пытаюсь найти документ по этому поводу, и кажется, что это предназначено для внутреннего использования, может быть удалено / изменено в будущем MNG-6589
Грег Домьян
Как использовать это? -1
hey_you
Это свойство, которое вы можете использовать так же, как и другие.
qoomon
я не уверен, что нам следует использовать этот ответ. Согласно этому билету, он является внутренним и может быть отправлен в любое время. Вот почему это нигде не задокументировано. По-прежнему нет чистого решения
Хиликус
22

Используйте directory-maven-plugin с directory-of target .

В отличие от других предложений:

  • Это решение работает для многомодульных проектов.
  • Это работает независимо от того, собираете ли вы весь проект или подмодуль.
  • Это работает независимо от того, запускаете ли вы maven из корневой папки или из подмодуля.
  • Нет необходимости устанавливать свойство относительного пути в каждом подмодуле!

Плагин позволяет вам установить свойство по вашему выбору для абсолютного пути любого из модулей проекта. В моем случае я установил его в корневой модуль ... В моем проекте root pom:

<plugin>
    <groupId>org.commonjava.maven.plugins</groupId>
    <artifactId>directory-maven-plugin</artifactId>
    <version>0.1</version>
    <executions>
        <execution>
            <id>directories</id>
            <goals>
                <goal>directory-of</goal>
            </goals>
            <phase>initialize</phase>
            <configuration>
                <property>myproject.basedir</property>
                <project>
                    <groupId>com.my.domain</groupId>
                    <artifactId>my-root-artifact</artifactId>
                </project>
            </configuration>
        </execution>
    </executions>
</plugin>

С этого момента $ {myproject.basedir} в любом подмодуле pom всегда имеет путь к корневому модулю проекта. И, конечно же, вы можете установить свойство для любого модуля, а не только для корня ...

Sparkyd
источник
Не ставьте «тест» на фазу. Вызывал у меня множество проблем. Отлично работает, как показано выше.
ElectronicBlacksmith
15

Я нашел решение своей проблемы: я ищу файлы свойств с помощью плагина Groovy Maven.

Поскольку мой файл свойств обязательно находится в текущем каталоге, в ../ или .. / .., я написал небольшой Groovy-код, который проверяет эти три папки.

Вот выдержка из моего pom.xml:

<!-- Use Groovy to search the location of the properties file. -->
<plugin>
    <groupId>org.codehaus.groovy.maven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.0-rc-5</version>
    <executions>
        <execution>
            <phase>validate</phase>
            <goals>
                <goal>execute</goal>
            </goals>
            <configuration>
                <source>
                    import java.io.File;
                    String p = project.properties['env-properties-file'];
                    File f = new File(p); 
                    if (!f.exists()) {
                        f = new File("../" + p);
                        if (!f.exists()) {
                            f = new File("../../" + p);
                        }
                    }
                    project.properties['env-properties-file-by-groovy'] = f.getAbsolutePath();
            </source>
            </configuration>
        </execution>
    </executions>
</plugin>
<!-- Now, I can load the properties file using the new 'env-properties-file-by-groovy' property. -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <file>${env-properties-file-by-groovy}</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

Это работает, но мне это не очень нравится.

Итак, если у вас есть лучшее решение, не стесняйтесь писать!

Ромен Линсолас
источник
12

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

<rant> Я слышал, что об этом говорят как об анти-шаблоне , но для каждого анти-шаблона есть реальный, законный вариант его использования, и мне надоело, что maven говорит мне, что я могу только следовать их шаблонам. </ разглагольствовать>

Итак, я нашел работу по использованию antrun. Попробуйте это в дочернем файле pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.7</version>
    <executions>
        <execution>
            <id>getMainBaseDir</id>
            <phase>validate</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <exportAntProperties>true</exportAntProperties>
                <target>
                    <!--Adjust the location below to your directory structure -->
                    <property name="main.basedir" location="./.." />
                    <echo message="main.basedir=${main.basedir}"/>
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

Если вы запустите, mvn verifyвы должны увидеть что-то вроде этого:

main:
     [echo] main.basedir=C:\src\parent.project.dir.name

Затем вы можете использовать ${main.basedir}любой из других плагинов и т. Д. Мне потребовалось время, чтобы разобраться в этом, так что надеюсь, что это поможет кому-то другому.

Джаред
источник
как передать его плагину maven-surefire?
Kalpesh Soni
7

Другая альтернатива:

в родительском помпе используйте:

<properties>
   <rootDir>${session.executionRootDirectory}</rootDir>
<properties>

В детских poms вы можете ссылаться на эту переменную.

Главное предостережение: он заставляет вас всегда выполнять команду из основного родительского каталога pom. Затем, если вы хотите запускать команды (например, тест) только для определенного модуля, используйте этот синтаксис:

mvn test --projects

Конфигурация верной настройки для параметризации переменной "path_to_test_data" может быть следующей:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire.plugin.version}</version>
    <configuration>
        <systemPropertyVariables>
            <path_to_test_data>${rootDir}/../testdata</path_to_test_data>
        </systemPropertyVariables>
    </configuration>
</plugin>
Франсуа Маро
источник
5

Следующий небольшой профиль работал у меня. Мне нужна была такая конфигурация для CheckStyle, которую я поместил в configкаталог в корне проекта, чтобы я мог запускать ее из основного модуля и из подмодулей.

<profile>
    <id>root-dir</id>
    <activation>
        <file>
            <exists>${project.basedir}/../../config/checkstyle.xml</exists>
        </file>
    </activation>
    <properties>
        <project.config.path>${project.basedir}/../config</project.config.path>
    </properties>
</profile>

Это не будет работать для вложенных модулей, но я уверен, что его можно изменить для этого, используя несколько профилей с разными exists. (Я понятия не имею, почему должно быть «../ ..» в теге проверки и просто «..» в самом переопределенном свойстве, но это работает только таким образом.)

Вик
источник
Я не знаю, почему это работает (лишнее ../), но это кажется самым чистым решением (у меня тоже были проблемы с конфигурацией checkstyle.xml)
RockMeetHardplace
5

В моем случае это работает так:

...
<properties>
  <main_dir>${project.parent.relativePath}/..</main_dir>
</properties>
...

<plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0-alpha-1</version>
        <executions>
          <execution>
            <phase>initialize</phase>
            <goals>
              <goal>read-project-properties</goal>
            </goals>
            <configuration>
              <files>
                 <file>${main_dir}/maven_custom.properties</file>
              </files>
            </configuration>
          </execution>
        </executions>
</plugin>
ilya1245
источник
3

Я нашел решение этой проблемы: используйте $ {parent.relativePath}

<parent>
    <artifactId>xxx</artifactId>
    <groupId>xxx</groupId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>..</relativePath>
</parent>
<build>
    <filters>
        <filter>${parent.relativePath}/src/main/filters/filter-${env}.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
Caille
источник
2
Это не всегда может быть безопасно; $ {parent.relativePath} может включать имя файла, например "../pom.xml"
pimlottc
3

Вы находитесь в проекте C, проект C - подмодуль B, а B - подмодуль A. Вы пытаетесь получить доступ к src/test/config/etcкаталогу модуля D из проекта C. D также является подмодулем A. Следующее выражение позволяет получить путь URI:

-Dparameter=file:/${basedir}/../../D/src/test/config/etc
Фатих Текин
источник
2
<plugins>
  <plugin>
    <groupId>org.codehaus.groovy.maven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.0</version>
    <executions>
      <execution>
        <phase>validate</phase>
        <goals>
          <goal>execute</goal>
        </goals>
        <configuration>
          <source>
            import java.io.File
            project.properties.parentdir = "${pom.basedir}"
            while (new File(new File(project.properties.parentdir).parent, 'pom.xml').exists()) {
                project.properties.parentdir = new File(project.properties.parentdir).parent
            }
          </source>
        </configuration>
      </execution>
    </executions>
  </plugin>
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-2</version>
    <executions>
      <execution>
        <phase>initialize</phase>
        <goals>
          <goal>read-project-properties</goal>
        </goals>
        <configuration>
          <files>
            <file>${parentdir}/build.properties</file>
          </files>
        </configuration>
      </execution>
    </executions>
  </plugin>
  ...

источник
1

В ответ на другой вопрос я показал, как можно расширить maven-properties-plugin для использования внешних дескрипторов свойств, определенных в зависимостях Maven.

Вы можете расширить эту идею, добавив несколько файлов-файлов дескрипторов, каждая из которых содержит имя среды как часть artifactId, содержащую $ {env} .properties. Затем вы можете использовать свойство, чтобы выбрать соответствующий файл jar и свойств, например:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>properties-ext-maven-plugin</artifactId>
  <version>0.0.1</version>
  <executions>
    <execution>
      <id>read-properties</id>
      <phase>initialize</phase>
      <goals>
        <goal>read-project-properties</goal>
      </goals>
    </execution>
  </executions>                              
  <configuration>
    <filePaths>
      <!--assume the descriptor project has a file in the root of the jar -->
      <filePath>${env}.properties</filePath>
    </filePaths>
  </configuration> 
  <dependencies>
    <!-- reference the properties jar for the particular environment-->
    <dependency>
      <groupId>some.descriptor.group</groupId>
      <artifactId>env-${env}-descriptor</artifactId>
      <version>0.0.1</version>
    </dependency>
  </dependencies>
</plugin>
Богатый продавец
источник
1

Я просто улучшаю Groovy-скрипт сверху, чтобы записать свойство в корневой родительский файл свойств:

import java.io.*;
String p = project.properties['env-properties-file']
File f = new File(p)
if (f.exists()) {
try{
FileWriter fstream = new FileWriter(f.getAbsolutePath())
BufferedWriter out = new BufferedWriter(fstream)
String propToSet = f.getAbsolutePath().substring(0, f.getAbsolutePath().lastIndexOf(File.separator))
if (File.separator != "/") {
propToSet = propToSet.replace(File.separator,File.separator+File.separator+File.separator)
}
out.write("jacoco.agent = " + propToSet + "/lib/jacocoagent.jar")
out.close()
}catch (Exception e){
}
}
String ret = "../"
while (!f.exists()) {
f = new File(ret + p)
ret+= "../"
}
project.properties['env-properties-file-by-groovy'] = f.getAbsolutePath()
Чарл
источник
0

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

пример для многомодульного

У pom верхнего уровня есть несвязанный проект конфигурации сборки и родительское приложение для модулей многомодульного проекта. Родительское приложение использует расширение, чтобы связать себя с проектом build-config и получить от него ресурсы. Он используется для переноса общих файлов конфигурации в модули. Это также может быть канал для недвижимости. Вы можете записать верхний каталог в файл свойств, используемый build-config. (кажется слишком сложным)

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

Питер Кан
источник
0

Это расширяет ответ romaintaz, который отлично решает проблему, а также четко указывает на отсутствующую функциональность maven. Я взял более позднюю версию плагина и добавил случай, когда проект может быть более чем на 3 уровня.

<pluginManagement>
  <plugins>
    ..
    <plugin>
      <groupId>org.codehaus.gmaven</groupId>
      <artifactId>groovy-maven-plugin</artifactId>
      <version>2.0</version>
    </plugin>
    ..
  </plugins>
</pluginManagement>

Я решил не использовать свойство для определения имени файла. Обратите внимание, что если build.properties не найден, он будет вращаться вечно. Я добавил обнаружение каталога .git, но не хотел слишком усложнять ответ, поэтому здесь он не показан.

  <plugin>
      <groupId>org.codehaus.gmaven</groupId>
      <artifactId>groovy-maven-plugin</artifactId>
      <executions>
          <execution>
              <phase>validate</phase>
              <goals>
                  <goal>execute</goal>
              </goals>
              <configuration>
                 <source>
                    import java.io.File;
                    String p = "build.properties";
                    while(true) {
                      File f = new File(p); 
                      if(f.exists()) {
                        project.properties['project-properties-file'] = f.getAbsolutePath();
                        break;
                      }
                      else {
                        p = "../${p}";
                      }
                    }
                </source>
              </configuration>
          </execution>
      </executions>
  </plugin>
Брюс Эдж
источник
0

Мне нужно было решить аналогичную проблему для локального репозитория, размещенного в основном проекте многомодульного проекта. По сути, реальный путь был ${basedir}/ lib. Наконец я остановился на этом в своем parent.pom:

<repository>
    <id>local-maven-repo</id>
    <url>file:///${basedir}/${project.parent.relativePath}/lib</url>
</repository>

Это basedirвсегда отображается для текущего локального модуля, нет способа получить путь к «главному» проекту (позор Maven). Некоторые из моих подмодулей на одну директорию глубже, некоторые на две директории глубже, но все они являются прямыми подмодулями родителя, который определяет URL-адрес репо.

Так что это не решает проблему в целом. Вы всегда можете объединить его с принятым ответом Клея и определить какое-то другое свойство - работает нормально, и его нужно переопределять только в тех случаях, когда значение from parent.pomнедостаточно хорошее. Или вы можете просто перенастроить плагин - что вы делаете только в артефактах POM (родительских элементах других подмодулей). Значение, извлеченное в свойство, вероятно, лучше, если оно вам нужно в большем количестве мест, особенно когда ничего не меняется в конфигурации плагина.

Использование basedirзначения было здесь важной частью, потому что URL-адрес file://${project.parent.relativePath}/libне помогал (я убрал одну косую черту, чтобы сделать его относительным). Было необходимо использовать свойство, которое дает мне хороший абсолютный путь, а затем перейти от него относительно.

Если путь не является URL / URI, это, вероятно, не проблема basedir.

дева47
источник
0

Я получил доступ к каталогу выше, используя $ {basedir} .. \ src \

Сеселин Моника
источник
1
да но нет. Для этого sub-module1он будет указывать на каталог module2, а не на main-project.
Romain Linsolas
-1

Вы пробовали ../../env_${env}.properties?

Обычно мы делаем следующее, когда module2 находится на том же уровне, что и подмодули

<modules>
    <module>../sub-module1</module>
    <module>../sub-module2</module>
    <module>../sub-module3</module>
</modules>

Я думаю, что ../ .. позволит вам прыгнуть на два уровня вверх. Если нет, вы можете связаться с авторами плагина и узнать, известна ли это проблема.

сал
источник
Если я помещу ../../env.props в основной pom.xml, то я получу сообщение об ошибке, когда Maven2 попытается собрать основной pom и весь модуль X. Эта конфигурация фактически работает только для всех
подмодулей