查找多模块Maven反应器项目的根目录


72

我想使用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}它将解析为模块的baseir。

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

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

Answers:


44

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

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


1
您可以为此链接到发行说明或文档吗?我找不到他们。
ChristofferHammarström18年

2
由于某些原因,@ChristofferHammarström仅在3.3.9的发行说明中显示为错误修复:maven.apache.org/docs/3.3.9/release-notes.html 但是,在Maven的Jira项目中进行深入研究,这里是它被引入,并且确实被标记为针对3.3.1的固定版本:issues.apache.org/jira/browse/MNG-5767
格雷戈里·约瑟夫(

2
可悲的是,他们“修复”了它,现在它只指向当前子项目,而不是实际的多项目根目录。因此,它并不比其他选项更好。
kaqqao

6
@kaqqao是的,很奇怪。我不能说我完全理解该错误报告的内容,但是当我尝试该错误时mvn help:evaluate -Dexpression=maven.multiModuleProjectDirectory对我起作用\ _(ツ)_ /¯编辑:我意识到,这似乎仅.mvn在我的项目顶部有一个文件夹时才有效!
格雷戈里·约瑟夫

2
尝试过Maven 3.6.3。结论:1)必须有一个.mvn文件夹,但是它可以为空2)mvn即使在子目录(模块)中运行命令,也可以正确报告整个项目的根目录。
wlnirvana

71

采用 ${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>

3
$ {session.executionRootDirectory}对我来说也是神奇的子弹。为什么不在maven.apache.org/pom.html中呢?
Bruce Edge

如果其他maven环境变量(例如$ {session.executionRootDirectory})不起作用,请尝试使用$ {project.basedir}。
Pradeeban Kathiravelu

7
我在Maven 3.3.9中尝试了$ {session.executionRootDirectory},它不再起作用了。您需要改为使用$ {user.dir}。我认为该选项不能令人满意,因为这意味着我只能独立运行父模块,而不能独立运行子模块。为此,您需要此stackoverflow.com/questions/1012402/…–
Dr4gon

24

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

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

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


5
您要管理所有这些“ / ..”和“ /../ ..”吗?我的意思是,确定该解决方案有效,但是它隐藏了项目的实际结构。
亨利·阿洛尼

我认为这应该是公认的答案。当您只构建一个单独的模块时,这甚至可以工作。
filip

当使用eclipse和m2e时,此解决方案有效,因为它不需要任何奇异的插件。
3urdoch

1
谢谢!对于简单项目,这是最优雅的方式。没有其他插件,只是显式覆盖。+1
尼古拉·舍甫琴科

20

有一个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中的任何地方使用。


3
我建议避免这种解决方案:如果您不执行该阶段(在示例中为initialize),则该属性将无法解决,因此,例如在clean/pre-clean阶段的子模块上需要该属性时,您将发现自己在复制/破解子模块上的config(已经在各种项目中看到了)。除非您有特殊要求(否则,您的项目并不特殊),请使用@karel的解决方案。
塞尔吉奥(Sergio)

1
这是一个很好的解决方案。对于较早的阶段,您只需指定即可<phase>pre-clean</phase>
armandino

5

正如其他人所建议的那样,目录移动插件是必经之路。但是,我发现它最适合“目录目录”目标,如此处所述:https : //stackoverflow.com/a/37965143/6498617

我更喜欢这样,因为在嵌套多模块poms的多模块项目中,使用基于lastir-basedir不适用于我。目标目录使您可以将属性设置为整个项目中任何模块的路径,包括根。它也比$ {session.executionRootDirectory}更好,因为它始终有效,而不管您是构建根模块还是子模块,而且无论您从哪个mvn来使用当前工作目录。


2

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

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


2

以下小档案对我有用。我需要为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的多个配置文件对其进行修改。(我不知道为什么在验证标签中应该有“ ../ ..”,在重写属性本身中只有“ ..”,但是它仅以此方式工作。)


那您是说baseir是$ {project.basedir} /../../吗?仅在将子项目放在父项目内的特定位置的情况下,此方法才有效。问题是,通常如何找到这条道路。
djjeck 2014年

basedir是`$ {project.basedir} /../ . Just some unique file is needed there (in my case it's checkstyle.xml ). And yes, this works (as I mentioned) for one-level of module nesting. Usually modules are put into subdirectories, so I don't consider here any other cases (but I'm sure something similar will work). The question was how to find something like $ {reactor.root.directory} . Here is my solution. But in my case I needed the / config`文件夹。稍加修改就可以获取根目录。对于嵌套模块,exist也可以使用具有不同的多个配置文件。
维克2014年

有不同的解决方案,但是我想找到一个简单的解决方案,它不需要复制粘贴到所有模块。
维克

1

我不知道找到多模块项目根目录的“好”方法。但是您也许可以改善当前的方法。

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

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


1
谢谢!如果只能了解文档并将其链接到构建生命周期,那么使用Assembly插件将是最好的。我只花了一个小时试图使其工作,然后放弃了……
ChristofferHammarström2010年

1

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


3
从引用模块的pom文件中,您如何知道该文件的位置?实际上,如果您知道该文件的位置,则不必读取其内容。
djjeck 2014年

如果您使用的是Git,并让Ant打电话,那就git rev-parse --show-toplevel可以了。
Ed Randall

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>

有用!


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>

0

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


那么,当我需要所有项目的始祖时,当某些子项目可能有自己的子项目时,它如何工作?
ChristofferHammarström,

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.