Properti Maven2 yang menunjukkan direktori induk

105

Saya memiliki proyek multi-modul, seperti ini:

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

Saya perlu mendefinisikan sekumpulan properti (yang bergantung pada lingkungan tempat saya ingin merilis proyek saya) di Maven2. Saya tidak akan menggunakan <properties>karena ada banyak properti ... Jadi, saya menggunakan plugin Properties Maven2 .

File properti terletak di main-project/direktori. Bagaimana saya bisa mengatur direktori yang benar di pom.xml utama, untuk menentukan ke anak mana pun tempat menemukan file properti?

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

Jika saya set saja <file>env_${env}.properties</file>, maka ketika Maven2 mengkompilasi modul pertama, ia tidak akan menemukan main-project/env_dev.propertiesfile tersebut. Jika saya mengatur <file>../env_${env}.properties</file>, maka kesalahan akan dimunculkan di tingkat induk, atau di tingkat sub-modul ...

Romain Linsolas
sumber
1
Cukup gunakan${maven.multiModuleProjectDirectory}
qoomon

Jawaban:

164

Coba tetapkan properti di setiap pom untuk menemukan direktori proyek utama.

Di induk:

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

Pada anak-anak:

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

Pada cucu:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>
Tanah liat
sumber
19
Apakah properti yang telah ditetapkan sebelumnya ini dihapus? ${parent.basedir}tidak lagi mengurai menjadi apa pun di 3.0.4 ...
matt5784
7
Ya, ini tidak berhasil. $ {project.parent.basedir} mengevaluasi ke null.
Jared
22
Saya telah berhasil ${project.basedir}/..tetapi itu benar-benar hanya berfungsi dalam proyek multi-modul yang berada dalam hierarki direktori yang ketat.
Jonathan
90
Mendesah. Sulit dipercaya, bahwa Maven membuat ini sangat sulit.
Stefan Haberl
5
Seperti Jonathan di atas, saya harus menggunakan jalur relatif, tetapi merasa yang terbaik adalah menggunakan file.separatorvariabel seperti ini<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired
29

Setidaknya dalam versi maven saat ini (3.6.0) dapat Anda manfaatkan ${maven.multiModuleProjectDirectory}

qoomon.dll
sumber
2
Mencoba menemukan dokumen tentang ini dan tampaknya ini dimaksudkan sebagai penggunaan internal, dapat dihapus / diubah di masa mendatang MNG-6589
Greg Domjan
Memanfaatkannya bagaimana? -1
hey_you
Ini adalah properti, Anda dapat menggunakan seperti yang Anda lakukan dengan orang lain.
qoomon
Saya tidak yakin kita harus menggunakan jawaban ini. Menurut tiket ini, itu internal dan bisa pergi kapan saja. Itu juga mengapa tidak didokumentasikan di mana pun. Masih ada solusi bersih
Hilikus
21

Gunakan direktori-maven-plugin dengan direktori-tujuan .

Tidak seperti saran lain:

  • Solusi ini berfungsi untuk proyek multi-modul.
  • Ini berfungsi baik Anda membangun keseluruhan proyek atau sub-modul.
  • Ini berfungsi baik Anda menjalankan maven dari folder root atau sub-modul.
  • Tidak perlu menyetel properti path relatif di setiap sub-modul!

Plugin ini memungkinkan Anda menyetel properti pilihan Anda ke jalur absolut dari modul proyek mana pun. Dalam kasus saya, saya mengaturnya ke modul root ... Dalam proyek saya root 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>

Sejak saat itu, $ {myproject.basedir} di setiap sub-modul pom selalu memiliki jalur modul root proyek. Dan tentu saja, Anda dapat menyetel properti ke modul apa pun, bukan hanya root ...

sparkyd
sumber
Jangan "menguji" fase tersebut. Menyebabkan saya berbagai masalah. Bekerja dengan baik seperti yang ditunjukkan di atas.
ElectronicBlacksmith
15

Saya telah menemukan solusi untuk memecahkan masalah saya: Saya mencari file properti menggunakan plugin Groovy Maven.

Karena file properti saya harus ada di direktori saat ini, di ../ atau di .. / .., saya menulis kode Groovy kecil yang memeriksa ketiga folder ini.

Berikut ini ekstrak my 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>

Ini berfungsi, tetapi saya tidak terlalu menyukainya.

Jadi, jika Anda memiliki solusi yang lebih baik, jangan ragu untuk memposting!

Romain Linsolas
sumber
12

Jadi masalah yang saya lihat adalah Anda tidak bisa mendapatkan path absolut ke direktori induk di maven.

<rant> Saya pernah mendengar hal ini dibicarakan sebagai anti-pola , tapi untuk setiap anti-pola ada kasus penggunaan yang nyata dan sah untuk itu, dan saya muak dengan maven mengatakan kepada saya bahwa saya hanya bisa mengikuti pola mereka. </ kata-kata kasar>

Jadi solusi yang saya temukan adalah dengan menggunakan antrun. Coba ini di pom.xml anak:

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

Jika Anda menjalankan mvn verifyAnda akan melihat sesuatu seperti ini:

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

Anda kemudian dapat menggunakan ${main.basedir}di salah satu plugin lain, dll. Butuh beberapa saat bagi saya untuk memikirkannya, jadi semoga ini membantu orang lain.

Jared
sumber
bagaimana cara menyebarkannya ke maven-surefire-plugin?
Kalpesh Soni
7

Alternatif lain:

di pom induk, gunakan:

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

Di pom anak-anak, Anda dapat merujuk variabel ini.

Peringatan utama: Ini memaksa Anda untuk selalu menjalankan perintah dari direktori induk pom utama. Kemudian jika Anda ingin menjalankan perintah (uji misalnya) hanya untuk beberapa modul tertentu, gunakan sintaks ini:

mvn test --projects

Konfigurasi yang pasti untuk membuat parameter variabel "path_to_test_data" mungkin menjadi:

<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>
Francois Marot
sumber
5

Profil kecil berikut berhasil untuk saya. Saya membutuhkan konfigurasi seperti itu untuk CheckStyle, yang saya masukkan ke configdirektori di root proyek, jadi saya dapat menjalankannya dari modul utama dan dari submodul.

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

Ini tidak akan bekerja untuk modul bersarang, tapi saya yakin itu dapat dimodifikasi untuk itu menggunakan beberapa profil dengan yang berbeda exists. (Saya tidak tahu mengapa harus ada "../ .." di tag verifikasi dan hanya ".." di properti yang diganti itu sendiri, tetapi hanya berfungsi dengan cara itu.)

Vic
sumber
Saya tidak tahu mengapa ini berfungsi (ekstra ../) tetapi ini sepertinya solusi terbersih (Saya juga mengalami masalah dengan konfigurasi checkstyle.xml)
RockMeetHardplace
5

Dalam kasus saya, ini berfungsi seperti ini:

...
<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>
ilya1245
sumber
3

Saya telah menemukan solusi untuk memecahkan masalah ini: gunakan $ {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>
Caille
sumber
2
Ini mungkin tidak selalu aman; $ {parent.relativePath} dapat menyertakan nama file, misalnya "../pom.xml"
pimlottc
3

Anda berada di proyek C, proyek C adalah submodul dari B dan B adalah submodul dari A. Anda mencoba untuk mencapai src/test/config/etcdirektori modul D dari proyek C. D juga merupakan submodul dari A. Ekspresi berikut memungkinkan untuk mendapatkan jalur URI:

-Dparameter=file:/${basedir}/../../D/src/test/config/etc
fatih tekin
sumber
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>
  ...

sumber
1

Dalam jawaban untuk pertanyaan lain, saya menunjukkan bagaimana maven-properties-plugin dapat diperluas untuk menggunakan deskriptor properti eksternal yang ditentukan dalam dependensi Maven.

Anda dapat memperluas ide itu untuk memiliki beberapa botol deskriptor, masing-masing dengan nama lingkungan sebagai bagian dari artifactId, berisi properti $ {env}. Kemudian Anda dapat menggunakan properti untuk memilih jar dan file properti yang sesuai, misalnya:

<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>
Penjual Kaya
sumber
1

Saya baru saja meningkatkan skrip groovy dari atas untuk menulis properti di file properti induk root:

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()
Tcharl
sumber
0

Saya rasa jika Anda menggunakan pola ekstensi yang digunakan dalam contoh untuk plugin findbugs & multimodule Anda mungkin dapat mengatur properti global yang terkait dengan jalur absolut. Ini menggunakan atasan

contoh untuk multi modul

Pom tingkat atas memiliki proyek build-config yang tidak terkait dan app-parent untuk modul proyek multimodule. App-parent menggunakan ekstensi untuk menautkan dirinya ke proyek build-config dan mendapatkan resource darinya. Ini digunakan untuk membawa file konfigurasi umum ke modul. Ini mungkin menjadi saluran untuk properti juga. Anda dapat menulis dir teratas ke file properti yang digunakan oleh build-config. (sepertinya terlalu rumit)

Masalahnya adalah bahwa level teratas baru harus ditambahkan ke proyek multi-modul agar ini berfungsi. Saya mencoba mengesampingkan langkah dengan proyek build-config yang benar-benar tidak terkait, tetapi itu kludgy dan tampak rapuh.

Peter Kahn
sumber
0

Ini memperluas jawaban romaintaz, yang luar biasa karena memecahkan masalah dan juga dengan jelas menunjukkan fungsionalitas maven yang hilang. Saya mengambil versi plugin yang lebih baru, dan menambahkan kasus di mana proyek bisa lebih dari 3 level.

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

Saya memilih untuk tidak menggunakan properti untuk menentukan nama file. Perhatikan jika build.properties tidak ditemukan, ini akan berputar selamanya. Saya menambahkan deteksi .git dir, tetapi tidak ingin terlalu memperumit respons sehingga tidak ditampilkan di sini.

  <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>
Bruce Edge
sumber
0

Saya perlu menyelesaikan masalah serupa untuk repositori lokal yang ditempatkan di proyek utama proyek multi-modul. Pada dasarnya jalur sebenarnya adalah ${basedir}/ lib. Akhirnya saya menetapkan ini di saya parent.pom:

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

Itu basedirselalu menunjukkan ke modul lokal saat ini, tidak ada cara untuk mendapatkan jalur ke proyek "master" (Maven memalukan). Beberapa submodul saya satu arah lebih dalam, beberapa dua arah lebih dalam, tetapi semuanya adalah submodul langsung dari induk yang mendefinisikan URL repo.

Jadi ini tidak menyelesaikan masalah secara umum. Anda selalu dapat menggabungkannya dengan jawaban yang diterima Clay dan menentukan beberapa properti lainnya - berfungsi dengan baik dan perlu didefinisikan ulang hanya untuk kasus-kasus di mana nilai dari parent.pomtidak cukup baik. Atau Anda mungkin hanya mengkonfigurasi ulang plugin - yang Anda lakukan hanya di artefak POM (induk dari sub-modul lain). Nilai yang diekstrak ke dalam properti mungkin lebih baik jika Anda membutuhkannya di lebih banyak tempat, terutama jika tidak ada perubahan dalam konfigurasi plugin.

Menggunakan basedirnilai adalah bagian penting di sini, karena URL file://${project.parent.relativePath}/libtidak ingin melakukan trik (saya menghapus satu garis miring untuk membuatnya relatif). Menggunakan properti yang memberi saya jalur absolut yang baik dan kemudian menjadi relatif darinya itu perlu.

Jika jalurnya bukan URL / URI, mungkin bukan masalah untuk dihilangkan basedir.

virgo47
sumber
0

Saya mengakses direktori di atas menggunakan $ {basedir} .. \ src \

Secelean Monica
sumber
1
ya tapi tidak. Untuk sub-module1, itu akan menunjuk pada direktori module2, bukan main-project.
Romain Linsolas
-1

Apakah kamu sudah mencobanya ../../env_${env}.properties?

Biasanya kami melakukan hal berikut ketika module2 berada pada level yang sama dengan sub-modul

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

Saya akan berpikir ../ .. akan membiarkan Anda melompat dua tingkat. Jika tidak, Anda mungkin ingin menghubungi penulis plugin dan melihat apakah ini adalah masalah yang diketahui.

sal
sumber
Jika saya meletakkan ../../env.props di pom.xml utama, maka saya akan mendapatkan error ketika Maven2 akan mencoba membangun pom utama, dan semua moduleX. Konfigurasi ini sebenarnya hanya akan berfungsi untuk semua sub-modul ...
Romain Linsolas