상위 디렉터리를 나타내는 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

답변:


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

7
네, 작동하지 않습니다. $ {project.parent.basedir}는 null로 평가됩니다.
Jared

22
나는 성공 ${project.basedir}/..했지만 실제로는 엄격한 디렉토리 계층 구조에있는 다중 모듈 프로젝트에서만 작동합니다.
Jonathan

90
한숨. 믿을 수 없네요, Maven이 이것을 너무 어렵게 만듭니다.
Stefan Haberl 2013

5
내가 상대 경로를 사용하지만, 느낌이 이상 조나단처럼 그것을 사용하는 것이 가장 좋습니다 file.separator같은 변수를<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired

29

적어도 현재 maven 버전 (3.6.0)에서는 다음을 사용할 수 있습니다. ${maven.multiModuleProjectDirectory}


2
이것에 대한 문서를 찾으려고하는데 이것이 내부 용도로 의도 된 것 같습니다. 향후 MNG-6589
Greg Domjan

어떻게 사용합니까? -1
hey_you

다른 사람과 마찬가지로 사용할 수있는 속성입니다.
qoomon

이 답변을 사용해야할지 모르겠습니다. 이 티켓 에 따르면 내부 티켓 이며 언제든지 갈 수 있습니다. 그것이 어디에도 문서화되지 않은 이유이기도합니다. 여전히 깨끗한 솔루션이 없습니다
Hilikus

21

목표 디렉토리와 함께 directory-maven-plugin을 사용하십시오 .

다른 제안과 달리 :

  • 이 솔루션은 다중 모듈 프로젝트에서 작동합니다.
  • 전체 프로젝트를 빌드하든 하위 모듈을 빌드하든 작동합니다.
  • 루트 폴더 또는 하위 모듈에서 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> 나는 이것이 반 패턴이라고 말하는 것을 들었지만, 모든 반 패턴에는 그것에 대한 실제적이고 합법적 인 사용 사례가 있으며, 나는 그들의 패턴 만 따를 수 있다고 말하는 메이븐이 지겨워 요. </ 폭언>

그래서 제가 찾은 일은 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

다음 작은 프로필이 저에게 효과적이었습니다. config프로젝트 루트의 디렉토리에 넣은 CheckStyle에 대한 이러한 구성이 필요 했기 때문에 메인 모듈과 하위 모듈에서 실행할 수 있습니다.

<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

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 종속성에 정의 된 외부 속성 설명자를 사용하도록 maven-properties-plugin을 확장하는 방법을 보여주었습니다.

이 아이디어를 확장하여 각각 $ {env} .properties를 포함하는 artifactId의 일부로 환경 이름이있는 여러 설명자 jar를 가질 수 있습니다. 그런 다음 속성을 사용하여 적절한 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

루트 상위 속성 파일에 속성을 작성하기 위해 위에서 그루비 스크립트를 개선했습니다.

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 plugin & multimodule 예제에서 사용 된 확장 패턴을 사용하면 절대 경로와 관련된 전역 속성을 설정할 수 있다고 생각합니다. 그것은 정상을 사용합니다

다중 모듈의 예

최상위 pom에는 관련없는 빌드 구성 프로젝트와 다중 모듈 프로젝트의 모듈에 대한 상위 앱이 있습니다. 앱 부모는 확장을 사용하여 빌드 구성 프로젝트에 연결하고 리소스를 얻습니다. 공통 구성 파일을 모듈로 전달하는 데 사용됩니다. 속성을위한 통로가 될 수도 있습니다. build-config에서 사용하는 속성 파일에 최상위 디렉토리를 쓸 수 있습니다. (너무 복잡해 보인다)

문제는이 작업을 수행하려면 다중 모듈 프로젝트에 새로운 최상위 레벨을 추가해야한다는 것입니다. 나는 진정으로 관련이없는 빌드 구성 프로젝트를 시도했지만 엉성하고 부서지기 쉬운 것처럼 보였습니다.


0

이것은 문제를 해결하고 maven의 누락 된 기능을 명확하게 지적하는 romaintaz의 대답을 확장합니다. 플러그인의 최신 버전을 선택하고 프로젝트가 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의 수치). 내 하위 모듈 중 일부는 한 단계 더 깊고 일부는 두 단계 더 깊지 만 모두 repo URL을 정의하는 부모의 직접 하위 모듈 입니다.

따라서 이것은 일반적으로 문제를 해결하지 않습니다. 항상 Clay의 허용 된 답변과 결합하여 다른 속성을 정의 할 수 있습니다. 잘 작동하며 값 parent.pom이 충분하지 않은 경우에만 재정의해야합니다 . 또는 POM 아티팩트 (다른 ​​하위 모듈의 부모)에서만 수행하는 플러그인을 다시 구성 할 수 있습니다. 속성으로 추출 된 값은 더 많은 곳에서 필요로하는 경우, 특히 플러그인 구성에 아무것도 변경되지 않은 경우 더 좋습니다.

사용하여 basedirURL이 때문에, 값에 여기에서 중요한 부분 한 file://${project.parent.relativePath}/lib트릭을 할 싶지 않았다 (나는 그것이 상대하기 위해 하나의 슬래시를 제거). 나에게 좋은 절대 경로를 제공하는 속성을 사용하고 그로부터 상대적으로가는 것이 필요했습니다.

경로가 URL / URI가 아닌 경우을 삭제하는 것은 문제가되지 않습니다 basedir.


0

$ {basedir} .. \ src \를 사용하여 위의 디렉토리에 액세스했습니다.


1
예,하지만 아니요. 를 들어 sub-module1, 그것은의 디렉토리에 가리 킵니다 module2아니라 main-project.
Romain Linsolas

-1

해봤 어 ../../env_${env}.properties?

일반적으로 module2가 하위 모듈과 동일한 수준에있을 때 다음을 수행합니다.

<modules>
    <module>../sub-module1</module>
    <module>../sub-module2</module>
    <module>../sub-module3</module>
</modules>

나는 ../ .. 당신이 두 단계를 뛰어 넘을 수 있다고 생각합니다. 그렇지 않은 경우 플러그인 작성자에게 연락하여 이것이 알려진 문제인지 확인하는 것이 좋습니다.


../../env.props를 main pom.xml에 넣으면 Maven2가 main pom과 모든 moduleX를 빌드하려고 할 때 오류가 발생합니다. 사실이 구성의 뜻은 ... 오직 모든 하위 모듈의 작동
로맹 Linsolas에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.