指示父目录的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,

Answers:


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

7
是的,这行不通。$ {project.parent.basedir}计算为空。
杰瑞德

22
我曾经取得过成功,${project.basedir}/..但实际上仅适用于严格目录层次结构中的多模块项目。
乔纳森

90
叹。令人难以置信的是,Maven很难做到这一点。
Stefan Haberl

5
像上面的Jonathan一样,我必须使用相对路径,但是感觉最好使用这样的file.separator变量<main.basedir>${project.basedir}${file.separator}..</main.basedir>
连线

29

至少在当前的Maven版本(3.6.0)中,您可以使用 ${maven.multiModuleProjectDirectory}


2
试图找到有关此文档的信息,看来这是内部使用,以后可能会被删除/更改MNG-6589
Greg Domjan

怎么利用?-1
hey_you

这是一个财产,您可以像对待他人一样使用。
qoomon

我不确定我们应该使用这个答案。根据这张票证,它是内部的,可能随时出现。这就是为什么它没有记录在任何地方的原因。仍然没有干净的解决方案
Hilikus

21

使用directory-maven-plugin和directory-of目标

与其他建议不同:

  • 该解决方案适用于多模块项目。
  • 无论您构建整个项目还是子模块,它都有效。
  • 无论您是从根文件夹还是子模块运行maven,它都可以工作。
  • 无需在每个子模块中设置相对路径属性!

该插件可让您将选择的属性设置为项目的任何模块的绝对路径。就我而言,我将其设置为根模块...在我的项目根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>

从那时起,任何子模块pom中的$ {myproject.basedir}始终具有项目根模块的路径。当然,您可以将属性设置为任何模块,而不仅仅是根目录...


不要对阶段进行“测试”。给我造成了各种各样的问题。如上所示,效果很好。
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

所以我发现的解决方法是使用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-plugin?
Kalpesh Soni

7

另一种选择:

在父pom中,使用:

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

在子poms中,可以引用此变量。

主要警告:强制您始终从主父pom目录执行命令。然后,如果您只想为某些特定模块运行命令(例如,测试),请使用以下语法:

mvn测试-项目

参数化“ path_to_test_data”变量的surefire的配置可能是:

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

3

您在项目C中,项目C是B的子模块,而B是A的子模块。您尝试src/test/config/etc从项目C 到达模块D的目录。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依赖项中定义的外部属性描述符。

您可以将该想法扩展为具有多个描述符jar,每个描述符jar的环境名称作为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项目和一个用于多模块项目模块的app-parent。app-parent使用扩展名将其自身链接到build-config项目并从中获取资源。这用于将通用配置文件传送到模块。它也可能是属性的管道。您可以将顶层目录写入到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总是显示当前本地模块,有没有办法让路径“主”项目(Maven的耻辱)。我的一些子模块深了一个目录,一些子目录深了两个,但是它们都是直接子模块定义回购URL的父级的。

因此,这通常无法解决问题。您可以始终将其与Clay接受的答案结合使用,并定义其他一些属性-效果很好,并且仅在from parent.pom值不够好的情况下才需要重新定义。或者,您可以只重新配置插件-您只能在POM工件(其他子模块的父对象)中进行此操作。如果您需要在更多地方使用,则提取到属性中的值可能会更好,尤其是在插件配置中没有任何更改的情况下。

basedir在其中使用值是必不可少的部分,因为URLfile://${project.parent.relativePath}/lib不想这样做(我删除了一个斜杠使其相对)。使用赋予我良好的绝对路径的属性,然后从中获得相对路径是必要的。

如果路径不是URL / URI,则drop可能不是问题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尝试构建主pom和所有moduleX时,我将得到一个错误。实际上,该配置仅适用于所有子模块...
Romain Linsolas,2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.