指示父目录的Maven2属性
我有一个多模块项目,就像这样:
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>
,那么会在父级别或任何子模块级别发生错误…
尝试在每个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>
我find了解决我的问题的解决scheme:我使用Groovy Maven插件search属性文件。
由于我的属性文件必须在当前目录中,在../或.. ..中,我写了一个小的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>
这工作,但我不喜欢它。
所以,如果你有更好的解决scheme,不要犹豫,发布!
所以,我所看到的问题是,你不能得到maven中的父目录的绝对path。
我听说这是一个反模式 ,但是对于每一个反模式,都有一个真正合法的使用案例,而且我厌恶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}
等等。花了我一些时间来解决这个问题,所以希望它能帮助别人。
就我而言,它的工作原理是这样的:
... <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>
以下小档案为我工作。 我需要这样一个configurationCheckStyle,我把它放到项目根目录下的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
几个configuration文件。 (我不知道为什么在validation标签中应该有“../ ..”,而在overriden属性本身中只是“..”,但它只能以这种方式工作。)
另一种select:
在父pom中,使用:
<properties> <rootDir>${session.executionRootDirectory}</rootDir> <properties>
在孩子的poms中,你可以引用这个variables。
主要警告:它迫使你总是执行从主父pom目录的命令。 那么如果你只想运行一些特定模块的命令(例如testing),使用下面的语法:
mvntesting – 项目
用于参数化“path_to_test_data”variables的surefireconfiguration可能是:
<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>
使用directory-maven-plugin和目录目录 。
不像其他的build议:
- 该解决scheme适用于多模块项目。
- 无论您是build立整个项目还是build立一个子模块,它都可以工作。
- 无论从根文件夹还是从子模块运行maven,它都可以工作。
- 无需在每个子模块中设置相对path属性!
该插件允许您将您所select的属性设置为任何项目模块的绝对path。 在我的情况下,我把它设置为根模块…在我的项目根目录:
<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}总是具有项目根模块的path。 当然,你可以设置属性为任何模块,而不仅仅是根…
我find了解决这个问题的解决scheme:使用$ {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>
您在项目C中,项目C是B的子模块,B是子模块A.您尝试从项目C到达模块D的src/test/config/etc
目录。D也是A的子模块。下面的expression式使得这成为可能获取URIpath:
-Dparameter=file:/${basedir}/../../D/src/test/config/etc
<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> ...
在另一个问题的答案中,我展示了如何将maven-properties-plugin扩展为使用Maven依赖关系中定义的外部属性描述符。
您可以扩展这个想法,使其具有多个描述符jar,每个描述符jar的环境名称都是artifactId的一部分,其中包含$ {env} .properties。 然后您可以使用该属性来select适当的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>
我只是从上面改进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()
我使用$ {basedir}来访问上面的目录。\ src \
你试过../../env_${env}.properties
?
通常情况下,我们在模块2与子模块处于同一级别时执行以下操作
<modules> <module>../sub-module1</module> <module>../sub-module2</module> <module>../sub-module3</module> </modules>
我会认为../ ..会让你跳两级。 如果没有,你可能想联系插件的作者,看看这是否是一个已知的问题。
我认为,如果你使用findbugs插件和多模块的例子中使用的扩展模式,你可能能够设置全局属性相关的绝对path。 它使用顶部
多模块示例
最高级别的pom有一个不相关的build-config项目和multimodule项目模块的app-parent。 app-parent使用扩展将自身链接到build-config项目并从中获取资源。 这用于将常见configuration文件传送到模块。 它也可能是物业的渠道。 您可以将顶层目录写入build-config所使用的属性文件。 (这似乎太复杂)
问题是,必须在多模块项目中添加新的顶层才能使其工作。 我试图与一个真正无关的构buildconfiguration项目迈出一步,但它是kludgy,似乎是脆弱的。
这扩展了romaintaz的答案,这很好解决了这个问题,也明确指出了maven的缺失function。 我拿起了一个更高版本的插件,并添加了项目可能超过3层的情况。
<pluginManagement> <plugins> .. <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>groovy-maven-plugin</artifactId> <version>2.0</version> </plugin> .. </plugins> </pluginManagement>
我select不使用属性来定义文件名。 注意,如果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>
我需要为多模块项目的主项目中的本地存储库解决类似的问题。 基本上真正的path是${basedir}
/ lib。 最后我在我的parent.pom
解决了这个问题:
<repository> <id>local-maven-repo</id> <url>file:///${basedir}/${project.parent.relativePath}/lib</url> </repository>
这个basedir
总是显示到当前的本地模块,没有办法获得“主”项目(Maven的耻辱)的path。 我的一些子模块是一个更深一层的,有些是更深一层的,但它们都是定义回购url的父节点的直接子模块 。
所以这一般不能解决问题。 你可以总是把它和Clay公认的答案结合起来,定义一些其他的属性 – 工作正常,只有在parent.pom
的值不够好的情况下才需要重新定义。 或者你可能只是重新configuration插件 – 你只在POM工件(其他子模块的父母)。 提取到属性中的值可能会更好,如果您在更多的地方需要它,尤其是当插件configuration中没有任何更改时。
在这个值中使用basedir
是这里的重要部分,因为URL file://${project.parent.relativePath}/lib
不想做这个伎俩(我删除了一个斜杠使之相对)。 使用给我绝对path的财产,然后去相对的是必要的。
当path不是URL / URI时,放弃basedir
可能不是这样的问题。
第一个答案应该工作。 在父子inheritance行中,在顶级POM中使用maven-default属性设置用户定义的属性(在本例中为<parent.base.directory>${project.parent.basedir}</parent.base.directory>
)将被设置,因为它遍历树。 换句话说, ${parent.base.directory}
将在不同的子POM中正确设置。
请注意,不应使用${parent.basedir}
作为用户定义的属性,因为它与maven-default ${project.parent.basedir}
属性相同。 否则,它会进入maven的recursionexpression式错误。 这就是为什么我在答案中使用${parent.base.directory}
。
希望这是解决问题的根本。