Thuộc tính Maven2 cho biết thư mục mẹ


105

Tôi có một dự án nhiều mô-đun, như dự án này:

main-project/
    module1/
    module2/
        sub-module1/
        sub-module2/
        sub-module3/
        ...
    module3/
    module4/
    ...

Tôi cần xác định một tập hợp các thuộc tính (phụ thuộc vào môi trường mà tôi muốn phát hành dự án của mình) trong Maven2. Tôi sẽ không sử dụng <properties>vì có rất nhiều thuộc tính ... Vì vậy, tôi sử dụng plugin Properties Maven2 .

Các tệp thuộc tính được đặt trong main-project/thư mục. Làm cách nào tôi có thể đặt đúng thư mục trong pom.xml chính, để chỉ định cho bất kỳ phần tử con nào để tìm tệp thuộc tính?

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

Nếu tôi chỉ đặt <file>env_${env}.properties</file>, thì khi Maven2 biên dịch mô-đun đầu tiên, nó sẽ không tìm thấy main-project/env_dev.propertiestệp. Nếu tôi đặt <file>../env_${env}.properties</file>, thì lỗi sẽ xuất hiện ở cấp độ chính hoặc ở bất kỳ cấp độ mô-đun phụ nào ...


1
Chỉ cần sử dụng${maven.multiModuleProjectDirectory}
qoomon

Câu trả lời:


164

Hãy thử thiết lập một thuộc tính trong mỗi pom để tìm thư mục chính của dự án.

Trong cha mẹ:

<properties>
    <main.basedir>${project.basedir}</main.basedir>
</properties>

Ở trẻ em:

<properties>
    <main.basedir>${project.parent.basedir}</main.basedir>
</properties>

Ở các cháu:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>

19
Các thuộc tính đặt trước này có bị xóa không? ${parent.basedir}phân tích không còn vào bất cứ điều gì trong 3.0.4 ...
matt5784

7
Vâng, điều này không hoạt động. $ {project.parent.basedir} đánh giá là null.
Jared

22
Tôi đã thành công với ${project.basedir}/..nhưng điều đó thực sự chỉ hoạt động trong các dự án nhiều mô-đun nằm trong một hệ thống phân cấp thư mục nghiêm ngặt.
Jonathan

90
Thở dài. Không thể tin được, Maven lại làm khó thế này.
Stefan Haberl

5
Giống như Jonathan ở trên, tôi phải sử dụng các đường dẫn tương đối, nhưng cảm thấy tốt nhất là sử dụng file.separatorbiến như thế này<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired

29

Ít nhất trong phiên bản maven hiện tại (3.6.0) bạn có thể sử dụng ${maven.multiModuleProjectDirectory}


2
Đang cố gắng tìm tài liệu về điều này và có vẻ như đây là mục đích sử dụng nội bộ, có thể bị xóa / thay đổi trong tương lai MNG-6589
Greg Domjan

Tận dụng nó như thế nào? -1
hey_you

Nó là một tài sản, bạn có thể sử dụng như cách bạn làm với những người khác.
qoomon

Tôi không chắc chúng ta nên sử dụng câu trả lời này. Theo vé này, nó là nội bộ và có thể đi bất cứ lúc nào. Đó cũng là lý do tại sao nó không được ghi lại ở bất cứ đâu. Vẫn không có giải pháp sạch
Hilikus

21

Sử dụng thư mục-maven-plugin với mục tiêu thư mục .

Không giống như các đề xuất khác:

  • Giải pháp này hoạt động cho các dự án nhiều mô-đun.
  • Nó hoạt động cho dù bạn xây dựng toàn bộ dự án hay một mô-đun con.
  • Nó hoạt động cho dù bạn chạy maven từ thư mục gốc hay một mô-đun con.
  • Không cần đặt thuộc tính đường dẫn tương đối trong mỗi và mọi mô-đun con!

Plugin cho phép bạn đặt một thuộc tính mà bạn lựa chọn thành đường dẫn tuyệt đối của bất kỳ mô-đun nào của dự án. Trong trường hợp của tôi, tôi đặt nó thành mô-đun gốc ... Trong root pom dự án của tôi:

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

Từ đó trở đi, $ {myproject.basedir} trong bất kỳ mô-đun con nào luôn có đường dẫn của mô-đun gốc của dự án. Và tất nhiên, bạn có thể đặt thuộc tính thành bất kỳ mô-đun nào, không chỉ gốc ...


Đừng đặt "thử nghiệm" cho giai đoạn. Gây ra cho tôi nhiều vấn đề. Hoạt động tuyệt vời như được hiển thị ở trên.
ElectronicBlacksmith

15

Tôi đã tìm thấy một giải pháp để giải quyết vấn đề của mình: Tôi tìm kiếm các tệp thuộc tính bằng cách sử dụng plugin Groovy Maven.

Vì tệp thuộc tính của tôi nhất thiết phải nằm trong thư mục hiện tại, trong ../ hoặc trong .. / .., tôi đã viết một mã Groovy nhỏ để kiểm tra ba thư mục này.

Đây là phần trích xuất của pom.xml của tôi:

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

Điều này đang hoạt động, nhưng tôi không thực sự thích nó.

Vì vậy, nếu bạn có một giải pháp tốt hơn, đừng ngần ngại đăng bài!


12

Vì vậy, vấn đề như tôi thấy là bạn không thể lấy đường dẫn tuyệt đối đến thư mục mẹ trong maven.

<rant> Tôi đã nghe điều này được nói đến như một mô hình phản đối , nhưng đối với mọi mô hình phản đối đều có trường hợp sử dụng thực sự, hợp pháp cho nó, và tôi phát ngán vì maven nói với tôi rằng tôi chỉ có thể làm theo mô hình của họ. </ rant>

Vì vậy, công việc xung quanh tôi tìm thấy là sử dụng antrun. Hãy thử điều này trong pom.xml con:

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

Nếu bạn chạy, mvn verifybạn sẽ thấy một cái gì đó như thế này:

main:
     [echo] main.basedir=C:\src\parent.project.dir.name

Sau đó, bạn có thể sử dụng ${main.basedir}trong bất kỳ plugin nào khác, v.v. Tôi đã mất một thời gian để tìm ra điều này, vì vậy hy vọng nó sẽ giúp ích cho người khác.


làm cách nào để chuyển nó cho maven-surefire-plugin?
Kalpesh Soni

7

Một thay thế khác:

trong pom mẹ, sử dụng:

<properties>
   <rootDir>${session.executionRootDirectory}</rootDir>
<properties>

Trong poms trẻ em, bạn có thể tham chiếu biến này.

Cảnh báo chính: Nó buộc bạn phải luôn thực thi lệnh từ thư mục pom chính. Sau đó, nếu bạn chỉ muốn chạy các lệnh (thử nghiệm chẳng hạn) cho một số mô-đun cụ thể, hãy sử dụng cú pháp sau:

mvn test - dự án

Cấu hình của surefire để tham số hóa biến "path_to_test_data" sau đó có thể là:

<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

Hồ sơ nhỏ sau đây đã làm việc cho tôi. Tôi cần một cấu hình như vậy cho CheckStyle, mà tôi đã đưa vào configthư mục trong thư mục gốc của dự án, vì vậy tôi có thể chạy nó từ mô-đun chính và từ các mô-đun con.

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

Nó sẽ không hoạt động cho các mô-đun lồng nhau, nhưng tôi chắc chắn rằng nó có thể được sửa đổi cho điều đó bằng cách sử dụng một số cấu hình với các mô-đun khác nhau exists. (Tôi không biết tại sao phải có "../ .." trong thẻ xác minh và chỉ ".." trong chính thuộc tính ghi đè, nhưng nó chỉ hoạt động theo cách đó.)


Tôi không biết tại sao điều này hoạt động (phần bổ sung ../) nhưng đây có vẻ như là giải pháp sạch sẽ nhất (tôi cũng gặp vấn đề với cấu hình checkstyle.xml)
RockMeetHardplace

5

Trong trường hợp của tôi, nó hoạt động như thế này:

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

Tôi đã tìm thấy giải pháp để giải quyết vấn đề này: sử dụng $ {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
Điều này có thể không phải lúc nào cũng an toàn; $ {parent.relativePath} có thể bao gồm tên tệp, ví dụ: "../pom.xml"
pimlottc

3

Bạn đang ở trong dự án C, dự án C là mô-đun con của B và B là mô-đun con của A. Bạn cố gắng truy cập thư mục của mô-đun D src/test/config/etctừ dự án C. D cũng là mô-đun con của A. Biểu thức sau giúp bạn có thể lấy đường dẫn 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

Trong một câu trả lời cho một câu hỏi khác, tôi đã chỉ ra cách maven-properties-plugin có thể được mở rộng để sử dụng các bộ mô tả thuộc tính bên ngoài được xác định trong phần phụ thuộc của Maven.

Bạn có thể mở rộng ý tưởng đó để có nhiều lọ trình mô tả, mỗi lọ có tên môi trường là một phần của tệp tạo tác, chứa $ {env} .properties. Sau đó, bạn có thể sử dụng thuộc tính để chọn tệp jar và thuộc tính thích hợp, ví dụ:

<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

Tôi chỉ cải thiện tập lệnh groovy từ trên để ghi thuộc tính vào tệp thuộc tính gốc gốc:

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

Tôi nghĩ rằng nếu bạn sử dụng mẫu mở rộng được sử dụng trong ví dụ cho plugin findbugs & multimodule, bạn có thể đặt thuộc tính toàn cục liên quan đến đường dẫn tuyệt đối. Nó sử dụng một đầu

ví dụ cho đa mô-đun

Pom cấp cao nhất có một dự án cấu hình xây dựng không liên quan và một ứng dụng mẹ cho các mô-đun của dự án đa mô-đun. Ứng dụng gốc sử dụng tiện ích mở rộng để liên kết chính nó với dự án cấu hình xây dựng và lấy tài nguyên từ nó. Điều này được sử dụng để mang các tệp cấu hình chung cho các mô-đun. Nó cũng có thể là một đường dẫn cho các tài sản. Bạn có thể ghi dòng trên cùng vào một tệp thuộc tính được cấu hình xây dựng sử dụng. (nó có vẻ quá phức tạp)

Vấn đề là một cấp cao nhất mới phải được thêm vào dự án nhiều mô-đun để làm cho nó hoạt động. Tôi đã cố gắng sang một bên với một dự án cấu hình xây dựng thực sự không liên quan nhưng nó rất khó và có vẻ dễ gãy.


0

Điều này mở rộng câu trả lời của romaintaz, điều tuyệt vời ở chỗ giải quyết được vấn đề và cũng chỉ ra rõ ràng chức năng còn thiếu của maven. Tôi đã chọn phiên bản plugin mới hơn và thêm trường hợp dự án có thể sâu hơn 3 cấp.

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

Tôi đã chọn không sử dụng thuộc tính để xác định tên tệp. Lưu ý nếu không tìm thấy build.properties, điều này sẽ quay mãi mãi. Tôi đã thêm phát hiện .git dir, nhưng không muốn làm phức tạp thêm phản hồi nên nó không được hiển thị ở đây.

  <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

Tôi cần giải quyết vấn đề tương tự cho kho lưu trữ cục bộ được đặt trong dự án chính của dự án đa mô-đun. Về cơ bản, đường dẫn thực là ${basedir}/ lib. Cuối cùng tôi đã giải quyết điều này trong parent.pom:

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

Điều đó basedirluôn cho thấy với mô-đun cục bộ hiện tại, không có cách nào để có được đường dẫn đến dự án "chính" (sự xấu hổ của Maven). Một số mô-đun con của tôi sâu hơn một bậc, một số thì sâu hơn hai bậc, nhưng tất cả chúng đều là mô-đun con trực tiếp của cha mẹ định nghĩa URL repo.

Vì vậy, điều này không giải quyết vấn đề nói chung. Bạn luôn có thể kết hợp nó với câu trả lời được chấp nhận của Clay và xác định một số thuộc tính khác - hoạt động tốt và chỉ cần được xác định lại đối với các trường hợp giá trị từ parent.pomkhông đủ tốt. Hoặc bạn có thể chỉ định cấu hình lại plugin - điều bạn chỉ thực hiện trong các tạo tác POM (cha mẹ của các mô-đun con khác). Giá trị được trích xuất thành thuộc tính có lẽ tốt hơn nếu bạn cần nó ở nhiều nơi hơn, đặc biệt là khi không có gì trong cấu hình plugin thay đổi.

Sử dụng basedirgiá trị là phần thiết yếu ở đây, vì URL file://${project.parent.relativePath}/libkhông muốn thực hiện thủ thuật (tôi đã loại bỏ một dấu gạch chéo để làm cho nó tương đối). Sử dụng tài sản mang lại cho tôi con đường tuyệt đối tốt và sau đó đi tương đối từ nó là cần thiết.

Khi đường dẫn không phải là URL / URI, nó có thể không phải là vấn đề như vậy để giảm basedir.


0

Tôi đã truy cập dir ở trên bằng cách sử dụng $ {basedir} .. \ src \


1
đúng nhưng không phải thế. Đối với sub-module1, nó sẽ trỏ trên thư mục của module2, không phải main-project.
Romain Linsolas

-1

Bạn đã thử ../../env_${env}.properties?

Thông thường, chúng tôi làm như sau khi module2 ở cùng cấp với các mô-đun con

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

Tôi sẽ nghĩ rằng ../ .. sẽ cho phép bạn nhảy lên hai cấp độ. Nếu không, bạn có thể muốn liên hệ với tác giả trình cắm và xem liệu đây có phải là sự cố đã biết hay không.


Nếu tôi đặt ../../env.props trong pom.xml chính, thì tôi sẽ gặp lỗi khi Maven2 cố gắng tạo pom chính và tất cả moduleX. Cấu hình này sẽ trên thực tế chỉ hoạt động cho tất cả các tiểu module ...
Romain Linsolas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.