Свойство Maven2, которое указывает родительский каталог
У меня есть проект с несколькими модулями, например:
main-project/
module1/
module2/
sub-module1/
sub-module2/
sub-module3/
...
module3/
module4/
...
Мне нужно определить набор свойств (которые зависят от среды, на которой я хочу выпустить мой проект) в Maven2.
Я не буду использовать <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
Попробуйте установить свойство в каждом 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>
Ответ 2
Я нашел решение для решения моей проблемы: я просматриваю файлы свойств с помощью плагина Groovy Maven.
Как мой файл свойств обязательно находится в текущем каталоге, в../или in../.., я написал небольшой 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>
Это работает, но мне это действительно не нравится.
Итак, если у вас есть лучшее решение, не стесняйтесь публиковать сообщения!
Ответ 3
Используйте каталог-maven-плагин с каталогом цели.
В отличие от других предложений:
- Это решение работает для многомодульных проектов.
- Это работает независимо от того, строите ли вы весь проект или субмодуль.
- Он работает независимо от того, запускаете ли вы 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 всегда имеет путь к корневому модулю проекта. И, конечно, вы можете установить свойство для любого модуля, а не только корень...
Ответ 4
Итак, проблема в том, что вы не можете получить абсолютный путь к родительскому каталогу в maven.
< напыщенная > Я слышал, что это обсуждалось как анти-шаблон, но для каждого анти-шаблона есть реальный, законный вариант использования, и я устал от maven говоря, что я могу только следовать их шаблонам. </rant>
Итак, работа, которую я нашел, - это использовать 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}
в любом из других плагинов и т.д. Мне понадобилось время, чтобы понять это, поэтому надейтесь, что это поможет кому-то другому.
Ответ 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>
Ответ 6
Следующий небольшой профиль работал у меня. Мне нужна такая конфигурация для 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
. (Я не знаю, почему в теге проверки должно быть "../.." в теге проверки и просто ".." ), но оно работает только таким образом.)
Ответ 7
Другая альтернатива:
в родительском поме используйте:
<properties>
<rootDir>${session.executionRootDirectory}</rootDir>
<properties>
В дочерних poms вы можете ссылаться на эту переменную.
Главное предостережение: оно заставляет вас всегда выполнять команду из основного родительского каталога pom. Затем, если вы хотите запускать команды (например, тестировать) только для определенного модуля, используйте этот синтаксис:
тест mvn --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>
Ответ 8
Я нашел решение для решения этой проблемы:
используйте ${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>
Ответ 9
Вы находитесь в проекте C, проект C является подмодулем B и B является подмодулем A. Вы пытаетесь добраться до каталога D src/test/config/etc
из проекта C. D также является подмодулем A. Следующее выражение делает это возможным для получить путь URI:
-Dparameter=file:/${basedir}/../../D/src/test/config/etc
Ответ 10
<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>
...
Ответ 11
В ответе на другой вопрос я показал, как расширение maven-properties-plugin можно расширить, чтобы использовать внешние дескрипторы свойств, определенные в зависимостях Maven.
Вы можете расширить эту идею, чтобы иметь несколько дескрипторов, каждый из которых имеет имя среды как часть artifactId, содержащую ${env}.properties. Затем вы можете использовать свойство, чтобы выбрать соответствующий файл jar и properties, например:
<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>
Ответ 12
Я просто улучшу groovy script сверху, чтобы записать свойство в файл родительских свойств root:
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()
Ответ 13
Я обратился к директории выше, используя ${basedir}..\src\
Ответ 14
Вы попробовали ../../env_${env}.properties
?
Обычно мы выполняем следующее, когда модуль2 находится на том же уровне, что и подмодули
<modules>
<module>../sub-module1</module>
<module>../sub-module2</module>
<module>../sub-module3</module>
</modules>
Я бы подумал, что.. /.. позволит вам вскочить на два уровня. Если нет, вы можете обратиться к плагину в авторах и узнать, является ли это известной проблемой.
Ответ 15
Я думаю, что если вы используете шаблон расширения, используемый в примере для плагина findbugs и multimodule, вы можете установить глобальные свойства, связанные с абсолютными путями. Он использует верхний
пример для нескольких модулей
У pom верхнего уровня есть несвязанный проект build-config и приложение-родитель для модулей проекта с несколькими модулями. Приложение-родитель использует расширение, чтобы связать себя с проектом build-config и получить от него ресурсы. Это используется для переноса общих конфигурационных файлов в модули. Это может быть канал для свойств. Вы могли бы написать верхний каталог в файл свойств, потребляемый build-config. (кажется слишком сложным)
Проблема заключается в том, что новый новый уровень должен быть добавлен в многомодульный проект, чтобы сделать эту работу. Я попытался сделать побочный шаг с действительно несвязанным проектом build-config, но он был клочковым и казался хрупким.
Ответ 16
Это расширяет запрос romaintaz, что является удивительным в том, что решает проблему, а также четко указывает на отсутствие функции maven.
Я взял более позднюю версию плагина и добавил случай, когда проект может быть более трех уровней.
<pluginManagement>
<plugins>
..
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>groovy-maven-plugin</artifactId>
<version>2.0</version>
</plugin>
..
</plugins>
</pluginManagement>
Я решил не использовать свойство для определения имени файла.
Обратите внимание, что если build.properties не найден, это будет вращаться навсегда. Я добавил детектор .git dir, но не хотел, чтобы он усложнил ответ, поэтому он не показан здесь.
<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>
Ответ 17
Мне нужно было решить подобную проблему для локального репозитория, размещенного в основном проекте мультимодульного проекта. По существу, реальный путь был ${basedir}
/lib. Наконец, я остановился на этом в своем parent.pom
:
<repository>
<id>local-maven-repo</id>
<url>file:///${basedir}/${project.parent.relativePath}/lib</url>
</repository>
То, что basedir
всегда отображается в текущем локальном модуле, не существует способа получить путь к "мастер-проекту" (позор Maven). Некоторые из моих подмодулей - это один дир глубже, некоторые из них - два, глубже, но все они являются прямыми подмодулями родителя, который определяет URL-адрес репо.
Таким образом, это не решает проблему в целом. Вы всегда можете комбинировать его с принятым ответом на Клей и определять какое-то другое свойство - отлично работает и нуждается в переопределении только для случаев, когда значение из parent.pom
недостаточно хорошее. Или вы можете просто перенастроить плагин, который вы делаете только в артефактах POM (родители других подмодулей). Значение, извлеченное в собственность, вероятно, лучше, если вам нужно это в большем количестве мест, особенно когда ничего в конфигурации плагина не изменяется.
Использование basedir
в значении было существенной частью здесь, потому что URL file://${project.parent.relativePath}/lib
не хотел делать трюк (я удалил одну косую черту, чтобы сделать ее относительной). Использование свойства, которое дает мне хороший абсолютный путь, а затем переход от него было необходимо.
Когда путь не является URL/URI, возможно, это не такая проблема, чтобы отказаться от basedir
.
Ответ 18
По крайней мере, в текущей версии maven (3.6.0) вы можете использовать ${maven.multiModuleProjectDirectory}
Ответ 19
Первый ответ должен работать. В строке наследования родительский-потом пользовательское свойство, заданное с помощью свойства maven-default в POM верхнего уровня (в данном случае <parent.base.directory>${project.parent.basedir}</parent.base.directory>
), будет установлено, когда оно пересекает дерево. Другими словами, ${parent.base.directory}
будет правильно установлен в другом дочернем POM.
Примечание. Вы не должны использовать ${parent.basedir}
как свое определяемое пользователем свойство, так как оно совпадает с свойством maven-default ${project.parent.basedir}
. В противном случае он получает ошибку рекурсивного выражения в maven. Поэтому я использую ${parent.base.directory}
в ответе.
Надеюсь, что это коренное решение проблемы.