81

有没有一种简单的方法可以找到像 Gradle 一样的多模块 Maven 项目的根rootDir


背景:

我想使用 maven-dependency-plugin 将我的多模块项目的所有子模块中的工件复制到与整个项目的根目录相关的目录中。

也就是说,我的布局看起来与此类似,名称已更改:

to-deploy/
my-project/
    module-a/
    module-b/
    more-modules-1/
        module-c/
        module-d/
    more-modules-2/
        module-e/
        module-f/
    ...

而且我希望从各自模块的目标目录中复制所有工件,my-project/../to-deploy以便最终得到

to-deploy/
    module-a.jar
    module-b.jar
    module-c.jar
    module-d.jar
    module-e.jar
    module-f.jar
my-project/
    ...

我可以在每个模块中使用相对路径来做到这一点,如下所示:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy</id>
                    <phase>install</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>${project.groupId}</groupId>
                                <artifactId>${project.artifactId}</artifactId>
                                <version>${project.version}</version>
                                <type>jar</type>
                                <outputDirectory>../../to-deploy</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>

但我宁愿不在<outputDirectory>元素中指定相对路径。我更喜欢类似的东西${reactor.root.directory}/../to-deploy,但我找不到这样的东西。

另外,如果有某种方法可以继承此 maven-dependency-plugin 配置,我更愿意,这样我就不必为每个模块指定它。

我还尝试从根 pom 继承自定义属性:

<properties>
    <myproject.root>${basedir}</myproject.root>
</properties>

但是当我尝试${myproject.root}在模块 POM 中使用时,${basedir}会解析为模块的 basedir。

另外,我发现http://labs.consol.de/lang/de/blog/maven/project-root-path-in-a-maven-multi-module-project/建议每个开发人员并且可能是连续的集成服务器应该在profiles.xml 文件中配置根目录,但我不认为这是一个解决方案。

那么有没有一种简单的方法可以找到多模块项目的根?

4

15 回答 15

77

利用${session.executionRootDirectory}

作为记录,${session.executionRootDirectory}在 Maven 3.0.3 的 pom 文件中为我工作。该属性将是您正在运行的目录,因此运行父项目,每个模块都可以获得该根目录的路径。

我将使用此属性的插件配置放在父 pom 中,以便它被继承。我只在我知道要在父项目上运行 Maven 时才选择的配置文件中使用它。这样,当我在子项目上运行 Maven 时,我不太可能以不希望的方式使用此变量(因为该变量不会是父项目的路径)。

例如,

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-artifact</id>
            <phase>package</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>${project.artifactId}</artifactId>
                        <version>${project.version}</version>
                        <type>${project.packaging}</type>
                    </artifactItem>
                </artifactItems>
                <outputDirectory>${session.executionRootDirectory}/target/</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
于 2011-10-06T15:30:02.500 回答
56

从 Maven 3.3.1 开始,您可以将${maven.multiModuleProjectDirectory}其用于此目的。(感谢https://stackoverflow.com/a/48879554/302789

编辑:这似乎只有当您.mvn在项目的根目录中有一个文件夹时才能正常工作。

于 2018-03-28T07:11:25.113 回答
28

我在我的项目中使用的东西是覆盖子模块 poms 中的属性。

    root:           <myproject.root>${basedir}</myproject.root>
    moduleA:        <myproject.root>${basedir}/..</myproject.root>
    other/moduleX:  <myproject.root>${basedir}/../..</myproject.root>

这样你仍然有相对路径,但你可以在根模块中定义一个插件,你的模块将继承它并正确替换 myproject.root。

于 2012-01-13T09:07:22.357 回答
22

有一个 maven 插件可以解决这个特殊问题:directory-maven-plugin

它会将项目的根路径分配给您选择的属性。请参阅highest-basedir文档中的目标。

例如:

<!-- Directory plugin to find parent root directory absolute path -->
<plugin>
  <groupId>org.commonjava.maven.plugins</groupId>
  <artifactId>directory-maven-plugin</artifactId>
  <version>0.1</version>
  <executions>
    <execution>
      <id>directories</id>
      <goals>
        <goal>highest-basedir</goal>
      </goals>
      <phase>initialize</phase>
      <configuration>
        <property>main.basedir</property>
      </configuration>
    </execution>
  </executions>
</plugin>

然后${main.basedir}在您的父/子 pom.xml 中的任何位置使用。

于 2013-11-28T11:16:44.713 回答
7

正如其他人所建议的那样,directory-maven-plugin这是要走的路。但是,我发现它最适合directory-of目标,如下所述:https ://stackoverflow.com/a/37965143/6498617 。

我更喜欢使用highest-basedir嵌套多模块 pom 的多模块项目对我不起作用。目标允许您为整个directory-of项目中任何模块的路径设置一个属性,当然包括根。它也比 . 好得多${session.executionRootDirectory},因为无论您构建根模块还是子模块,并且无论您 mvn 来自哪个当前工作目录,它都始终有效。

于 2016-06-22T10:35:34.587 回答
3

以下小配置文件对我有用。我需要为 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's 的配置文件对其进行修改。(我不知道为什么验证标签中应该有“../..”,而被覆盖的属性本身只有“..”,但它只能以这种方式工作。)

于 2013-07-02T10:44:55.250 回答
3

目前,Maven 不提供开箱即用的“根项目目录路径”属性。
«根项目» 表示«最顶层» 父项目。

请参考票证并考虑投票:[MNG-7038] 引入公共属性以指向(多模块)项目的根目录 - ASF JIRA

于 2021-08-23T08:22:05.157 回答
2

我遇到了类似的问题,因为我需要在项目之间复制文件。Maven 所做的事情是合乎逻辑的,因为它将使安装在存储库中的 pom.xml 远离硬编码值。

我的解决方案是将复制的目录放入 Maven 工件中,然后使用 Ant 提取/复制

于 2012-06-06T10:34:24.847 回答
1

另一种解决方案是使用 ant 任务将“rootdir=${basedir}”写入根项目中的 target/root.properties,然后使用Properties Plugin重新读取该文件。我没有尝试过我自己,但我想它应该工作..?

于 2010-12-14T11:18:39.743 回答
1

我不知道找到多模块项目的根的“好”方法。但是你也许可以改进一点你目前的方法。

第一种选择是直接在根项目下创建一个附加模块,将所有 EAR 声明为其中的依赖项,并用于dependency:copy-dependencies将模块的依赖项复制到to-deploy目录(相对)。是的,路径仍然是相对的,但由于依赖插件配置是集中的,我不觉得它很烦人。

第二种选择是使用Maven Assembly Plugin而不是Maven Dependency Plugin来创建使用dir格式的分发(这将在目录中创建分发)。这实际上是我会做的。

于 2010-06-21T14:04:35.130 回答
1

除了使用绝对根路径外,在某些情况下,我还有另一种解决问题的方法。

使用 maven 插件 combine.children 功能,参考:maven 插件

我可以写我的代码:

父pom:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
          <execution>
              <id>copy-dependencies</id>
              <phase>package</phase>
              <goals>
                  <goal>copy-dependencies</goal>
              </goals>
              <configuration>
                  <includeScope>runtime</includeScope>
                  <outputDirectory combine.children="override">${project.basedir}/to-deploy</outputDirectory>
              </configuration>
          </execution>
      </executions>
    </plugin>
  </plugins>
</build>

或者写插件管理,如果父 pom 不使用这个插件。

孩子 pom:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
          <execution>
              <!--same as parent plugin id-->
              <id>copy-dependencies</id>
              <configuration>
                  <outputDirectory combine.children="override">${project.parent.basedir}/to-deploy</outputDirectory>
              </configuration>
          </execution>
      </executions>
    </plugin>
  </plugins>
</build>

类似的方式孙子pom:

<outputDirectory combine.children="override">${project.parent.parent.basedir}/to-deploy</outputDirectory>
于 2022-02-07T13:14:35.207 回答
0

对于 Maven 3.6.1,从子项目中,${parent.basedir} 返回父项目的完全限定目录。

于 2019-10-25T03:49:43.817 回答
0

我有 ${project.parent.basedir} 的父 pom 的根目录。

于 2020-09-16T16:52:40.143 回答
0

这样:在某个父项目的属性中,我有稍后需要关联的文件,这就是为什么我在任何地方都需要绝对路径的原因。所以,我在groovy的帮助下得到了它:

<properties>    
<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); 
          } 
        } 
        // setting path together with file name in variable xyz_format 
        project.properties['xyz_format'] =f.getAbsolutePath() 
                            + File.separator 
                            + "abc_format.xml"; 
</source>
</properties>   

接着:

  <properties>
     <snapshots>http://localhost:8081/snapshots<snapshots>
     <releases>http://localhost:8081/releases</releases>
     <sonar>jdbc:oracle:thin:sonar/sonar@localhost/XE</sonar>
     <sonar.jdbc.username>sonar</sonar.jdbc.username>
     <format.conf> ${xyz_format}</format.conf>  <---- here is it!
    </properties>

有用!

于 2016-03-26T14:25:25.653 回答
0

你可以用这样的东西。请注意,您必须定义两个配置文件 - 一个将为根目录激活,另一个为子目录激活。显然,这假设孩子将具有相同的结构,但这很容易适应。

    <profiles>
        <profile>
            <id>root-dir</id>
            <activation>
                <file>
                    <exists>${basedir}/lib</exists>
                </file>
            </activation>
            <properties>
                <project.libdir>${basedir}/lib</project.libdir>
            </properties>
        </profile>
        <profile>
            <id>child-dir</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <project.libdir>${basedir}/../../lib</project.libdir>
            </properties>
        </profile>
    </profiles>
于 2019-09-15T16:19:47.333 回答