Властивість Maven2, яка вказує батьківський каталог


105

У мене є багатомодульний проект, як цей:

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

Відповіді:


164

Спробуйте встановити властивість у кожному 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} оцінює нуль.
Джаред

22
Я мав успіх у, ${project.basedir}/..але це справді працює лише в мультимодульних проектах, які перебувають у строгій ієрархії каталогів.
Джонатан

90
Зітхнути. Неймовірно, що Мейвен робить це так важко.
Стефан Хаберль

5
Як і Джонатан вище, я повинен використовувати відносні шляхи, але вважаю, що найкраще використовувати file.separatorзмінну на зразок цієї<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired

29

Принаймні, у поточній версії Maven (3.6.0), якою ви можете скористатися ${maven.multiModuleProjectDirectory}


2
Намагаючись знайти документа з цього питання, і здається, що це призначено як внутрішнє використання, його можна буде видалити / змінити в майбутньому MNG-6589
Greg Domjan

Як скористатися ним? -1
hey_you

Це властивість, яку можна використовувати так, як ви робили з іншими.
qoomon

Я не впевнений, що нам слід використовувати цю відповідь. Відповідно до цього квитка, він внутрішній і може вийти в будь-який час. Ось чому це ніде не задокументовано. Ще немає чистого рішення
Хілікус

21

Використовуйте довідник-maven-плагін із каталогу-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 завжди має шлях до кореневого модуля проекту. І звичайно, ви можете встановити властивість на будь-який модуль, а не тільки на корінь ...


Не ставте "тест" для фази. Викликав у мене різноманітні проблеми. Чудово працює, як показано вище.
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> Я чула, як це говорилося як про анти-шаблон , але для кожного анти-шаблону є справжній законний випадок використання для цього, і мені нудно, щоб Мене сказав, що я можу слідувати лише їх моделям. </ rant>

Тому робота, яку я знайшов, - використовувати мурашник. Спробуйте це в дитині 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?
Калпеш Соні

7

Ще одна альтернатива:

в батьківській пом, використовуйте:

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

У дитячих пісах можна посилатися на цю змінну.

Основний застереження: Це змушує вас завжди виконувати команди з головного батьківського каталогу pom. Тоді, якщо ви хочете запускати команди (наприклад, тест) лише для певного модуля, використовуйте цей синтаксис:

mvn test --проекти

Конфігурація надійного файлу для параметризації змінної "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>

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>

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-властивості для використання зовнішніх дескрипторів властивостей, визначених у залежностях Maven.

Ви можете розширити цю ідею, щоб мати кілька банок дескриптора, кожна з іменами середовища як частина артефакту, що містить $ {env}. Властивості. Потім ви можете скористатися властивістю, щоб вибрати відповідний файл 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

Я думаю, що якщо ви будете використовувати шаблон розширення, який використовується у прикладі для плагіну find і багатомодуля, ви зможете встановити глобальні властивості, пов'язані з абсолютними шляхами. Він використовує верх

приклад для мультимодуля

Пом на верхньому рівні має незв'язаний проект збирання-конфігурації та додаток для модулів мультимодульного проекту. Родильник додатків використовує розширення, щоб прив'язати себе до проекту build-config та отримати ресурси з нього. Це використовується для перенесення загальних файлів конфігурацій до модулів. Це може бути також каналом для властивостей. Ви можете записати верхній dir у файл властивостей, який споживає 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 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>

0

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

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

Це basedirзавжди показує поточний локальний модуль, немає способу пройти шлях до "майстерного" проекту (сором Мейвена). Деякі з моїх підмодулів на один dir глибші, деякі на два dir глибші, але всі вони є прямими підмодулями батьків, що визначає URL-адресу репо.

Тож це взагалі не вирішує проблему. Ви завжди можете комбінувати його з прийнятою відповіддю Clay та визначити якусь іншу властивість - працює чудово і її потрібно переосмислити лише у випадках, коли значення зparent.pom недостатньо хорошого. Або ви можете просто перенастроїти плагін - який ви робите лише в артефактах POM (батьки інших підмодулів). Значення, вилучене у власність, ймовірно, краще, якщо вам це потрібно в більшій кількості місць, особливо коли нічого в конфігурації плагіна не змінюється.

Використання basedirзначення було важливою частиною тут, оскільки URLfile://${project.parent.relativePath}/lib не хотів робити трюк (я видалив одну косу рису, щоб зробити її відносною). Використовувати властивість, яка дає мені хороший абсолютний шлях, а потім перехід відносно від нього було необхідним.

Коли шлях не є URL / URI, це, ймовірно, не має такої проблеми basedir .



-1

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

Зазвичай ми робимо наступне, коли module2 знаходиться на одному рівні з підмодулями

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

Думаю, ../ .. дозволить вам піднятися на два рівні. Якщо ні, то, можливо, ви захочете зв’язатись із автором плагіну та побачити, чи це відома проблема.


Якщо я поставлю ../../env.props в основний pom.xml, тоді я отримаю помилку, коли Maven2 спробує створити основну пом і всі moduleX. Фактично ця конфігурація працює лише для всіх
підмодулів
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.