programing tip

상위 디렉터리를 나타내는 Maven2 속성

itbloger 2020. 8. 23. 08:38
반응형

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

목표 디렉토리와 함께 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}에는 항상 프로젝트 루트 모듈의 경로가 있습니다. 물론, 루트뿐만 아니라 모든 모듈에 속성을 설정할 수 있습니다.


내 문제를 해결할 해결책을 찾았습니다. 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>

이것은 효과가 있지만 정말 마음에 들지 않습니다.

따라서 더 나은 솔루션이 있다면 주저하지 말고 게시하십시오!


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


그래서 내가 보는 문제는 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}다른 플러그인 등에서 사용할 수 있습니다 .이 문제를 파악하는 데 시간이 걸렸으므로 다른 사람에게 도움이되기를 바랍니다.


다음 작은 프로필이 저에게 효과적이었습니다. 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. (확인 태그에 "../ .."이 있어야하고 재정의 된 속성 자체에 ".."만 있어야하는 이유를 모르겠지만 그 방식으로 만 작동합니다.)


제 경우에는 다음과 같이 작동합니다.

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

또 다른 대안 :

부모 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>

이 문제를 해결할 해결책을 찾았습니다. $ {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의 하위 모듈입니다. src/test/config/etc프로젝트 C에서 모듈 D의 디렉토리 에 도달하려고합니다 . D는 A의 하위 모듈이기도합니다. 다음 표현식을 통해 URI 경로를 가져올 수 있습니다.

-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 종속성에 정의 된 외부 속성 설명자를 사용하도록 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>

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

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?

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

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

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


I think that if you use the extension pattern used in the example for findbugs plugin & multimodule you may be able to set global properties related to absolute paths. It uses a top

example for multi module

The top level pom has an unrelated build-config project and a app-parent for the modules of the multimodule project. The app-parent uses extension to link itself to the build-config project and obtain resources from it. This is used to carry common config files to the modules. It may be a conduit for properties as well. You could write the top dir to a property file consumed by the build-config. (it seems too complex)

The problem is that a new top level must be added to the multi-module project to make this work. I tried to side step with a truly unrelated build-config project but it was kludgy and seemed brittle.


This extends romaintaz's answer, which is awesome in that solves the problem and also clearly points out maven's missing functionality. I picked up a later version of the plugin, and added the case where the project could be more than 3 levels deep.

<pluginManagement>
  <plugins>
    ..
    <plugin>
      <groupId>org.codehaus.gmaven</groupId>
      <artifactId>groovy-maven-plugin</artifactId>
      <version>2.0</version>
    </plugin>
    ..
  </plugins>
</pluginManagement>

I elected not to use a property to define the filename. Note if the build.properties is not found this will spin forever. I added a .git dir detection, but didn't want to over complicate the response so it's not shown here.

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

I needed to solve similar problem for local repository placed in the main project of multi-module project. Essentially the real path was ${basedir}/lib. Finally I settled on this in my parent.pom:

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

That basedir always shows to current local module, there is no way to get path to "master" project (Maven's shame). Some of my submodules are one dir deeper, some are two dirs deeper, but all of them are direct submodules of the parent that defines the repo URL.

So this does not resolve the problem in general. You may always combine it with Clay's accepted answer and define some other property - works fine and needs to be redefined only for cases where the value from parent.pom is not good enough. Or you may just reconfigure the plugin - which you do only in POM artifacts (parents of other sub-modules). Value extracted into property is probably better if you need it on more places, especially when nothing in the plugin configuration changes.

Using basedir in the value was the essential part here, because URL file://${project.parent.relativePath}/lib did not want to do the trick (I removed one slash to make it relative). Using property that gives me good absolute path and then going relative from it was necessary.

When the path is not URL/URI, it probably is not such a problem to drop basedir.

참고URL : https://stackoverflow.com/questions/1012402/maven2-property-that-indicates-the-parent-directory

반응형