【问题标题】:Maven2 property that indicates the parent directory指示父目录的 Maven2 属性
【发布时间】:2010-11-03 23:40:58
【问题描述】:

我有一个多模块项目,比如这个:

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

我需要在 Maven2 中定义一组属性(取决于我想要发布我的项目的环境)。 我不会使用<properties>,因为有很多属性... 因此,我使用Properties Maven2 plugin

属性文件位于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>

如果我只设置&lt;file&gt;env_${env}.properties&lt;/file&gt;,那么当Maven2编译第一个模块时,会找不到main-project/env_dev.properties文件。如果我设置&lt;file&gt;../env_${env}.properties&lt;/file&gt;,则会在父级或任何子模块级引发错误...

【问题讨论】:

  • 只要使用${maven.multiModuleProjectDirectory}

标签: maven-2 properties


【解决方案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 时,我会得到一个错误。此配置实际上仅适用于所有子模块...
【解决方案2】:

我找到了解决问题的方法:我使用 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>

这行得通,但我不太喜欢它。

所以,如果您有更好的解决方案,请不要犹豫发布!

【讨论】:

    【解决方案3】:

    尝试在每个 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>
    

    【讨论】:

    • 这些预设属性是否被删除? ${parent.basedir} 不再解析为 3.0.4 中的任何内容...
    • 是的,这行不通。 ${project.parent.basedir} 计算结果为 null。
    • 我在${project.basedir}/.. 上取得了成功,但这确实只适用于严格目录层次结构中的多模块项目。
    • 叹息。难以置信,Maven 让这变得如此困难。
    • 像上面的乔纳森我必须使用相对路径,但感觉最好使用file.separator这样的变量&lt;main.basedir&gt;${project.basedir}${file.separator}..&lt;/main.basedir&gt;
    【解决方案4】:

    answer to another question 中,我展示了如何扩展 maven-properties-plugin 以使用 Maven 依赖项中定义的外部属性描述符。

    您可以将该想法扩展为拥有多个描述符 jar,每个描述符 jar 都将环境名称作为 artifactId 的一部分,其中包含 ${env}.properties。然后就可以使用property来选择合适的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>
    

    【讨论】:

      【解决方案5】:
      <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>
        ...
      

      【讨论】:

        【解决方案6】:

        我认为,如果您使用示例中用于 findbugs 插件和多模块的扩展模式,您可能能够设置与绝对路径相关的全局属性。它使用顶部

        example for multi module

        顶级 pom 有一个不相关的 build-config 项目和一个 app-parent 用于多模块项目的模块。 app-parent 使用扩展将自己链接到 build-config 项目并从中获取资源。这用于将通用配置文件传送到模块。它也可能是属性的管道。您可以将顶部目录写入 build-config 使用的属性文件。 (好像太复杂了)

        问题是必须在多模块项目中添加一个新的顶层才能使其工作。我试图避开一个真正不相关的构建配置项目,但它很笨拙而且看起来很脆弱。

        【讨论】:

          【解决方案7】:

          我只是从上面改进了 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()
          

          【讨论】:

            【解决方案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>
            

            【讨论】:

            • 这可能并不总是安全的; ${parent.relativePath} 可以包含文件名,例如“../pom.xml”
            【解决方案9】:

            所以我看到的问题是您无法在 maven 中获取父目录的绝对路径。

            I've heard this talked about as an anti-pattern,但是对于每个反模式都有真实、合法的用例,我厌倦了 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-plugin?
            【解决方案10】:

            就我而言,它是这样工作的:

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

            【讨论】:

              【解决方案11】:

              您在项目C中,项目C是B的子模块,B是A的子模块。您尝试从项目C到达模块D的src/test/config/etc目录。D也是A的子模块。下面的表达式使这成为可能获取 URI 路径:

              -Dparameter=file:/${basedir}/../../D/src/test/config/etc
              

              【讨论】:

                【解决方案12】:

                以下小配置文件对我有用。我需要为 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 配置问题)
                【解决方案13】:

                这扩展了 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>
                

                【讨论】:

                  【解决方案14】:

                  我需要解决放置在多模块项目主项目中的本地存储库的类似问题。本质上,真正的路径是${basedir}/lib。最后我在parent.pom 中解决了这个问题:

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

                  basedir 总是显示给当前本地模块,没有办法获得“主”项目的路径(Maven 的耻辱)。我的一些子模块更深一个目录,一些更深两个目录,但它们都是定义 repo URL 的父级的直接子模块

                  所以这通常不能解决问题。您可能总是将它与 Clay 接受的答案结合起来并定义一些其他属性 - 工作正常,仅在 parent.pom 的值不够好的情况下才需要重新定义。或者您可能只是重新配置插件 - 您只在 POM 工件(其他子模块的父级)中执行此操作。如果您在更多地方需要提取到属性中的值可能会更好,尤其是当插件配置中没有任何更改时。

                  在值中使用basedir 是这里必不可少的部分,因为URL file://${project.parent.relativePath}/lib 不想这样做(我删除了一个斜杠以使其相对)。使用能给我提供良好绝对路径的属性,然后从它开始相对是必要的。

                  当路径不是 URL/URI 时,删除basedir 可能不是这样的问题。

                  【讨论】:

                    【解决方案15】:

                    另一种选择:

                    在父 pom 中,使用:

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

                    在子 pom 中,你可以引用这个变量。

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

                    mvn 测试 --projects

                    surefire 参数化“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>
                    

                    【讨论】:

                      【解决方案16】:

                      我使用 ${basedir}..\src\

                      访问了上面的目录

                      【讨论】:

                      • 是但不是。对于sub-module1,它将指向module2 的目录,而不是main-project
                      【解决方案17】:

                      使用directory-maven-plugin with directory-of goal

                      与其他建议不同:

                      • 此解决方案适用于多模块项目。
                      • 无论您构建整个项目还是子模块,它都可以工作。
                      • 无论您是从根文件夹还是子模块运行 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} 始终具有项目根模块的路径。当然,您可以将属性设置为任何模块,而不仅仅是根...

                      【讨论】:

                      • 不要将“测试”用于阶段。给我带来了各种各样的问题。如上所示,效果很好。
                      【解决方案18】:

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

                      【讨论】:

                      • 试图找到有关此的文档,似乎这是作为内部使用,将来可能会被删除/更改MNG-6589
                      • 它是一个属性,你可以像对待其他人一样使用它。
                      • 我不确定我们应该使用这个答案。根据this ticket,它是内部的,可能随时消失。这也是为什么它没有在任何地方记录的原因。仍然没有干净的解决方案
                      • 它解析为我在 Windows 10 上的用户主页。
                      • 它现在可能已经/已经被删除了。但是 2009 年接受的答案中的 ${project.parent.basedir} 属性也是如此,而且这些属性不是内部的。所以......无论如何,生命都是危险的:P
                      【解决方案19】:

                      这在多项目设置中对我有用

                      在父 pom 文件中:

                      &lt;properties&gt; &lt;main.basedir&gt;${project.basedir}\..&lt;/main.basedir&gt; &lt;/properties&gt;

                      在子项目中访问这些属性,例如:

                      ${main.basedir}/
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-08-10
                        • 2017-01-30
                        • 2015-10-27
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多