Proprietà Maven2 che indica la directory padre


105

Ho un progetto multi-moduli, come questo:

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

Ho bisogno di definire una serie di proprietà (che dipendono dall'ambiente su cui voglio rilasciare il mio progetto) in Maven2. Non userò <properties>perché ci sono molte proprietà ... Quindi, uso il plugin Proprietà Maven2 .

I file delle proprietà si trovano nella main-project/directory. Come posso impostare la directory corretta nel pom.xml principale, in modo da specificare a tutti i bambini dove trovare il file delle proprietà?

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

Se imposto solo <file>env_${env}.properties</file>, quando Maven2 compila il primo modulo, non troverà il main-project/env_dev.propertiesfile. Se imposto <file>../env_${env}.properties</file>, verrà generato un errore a livello di genitore, o a qualsiasi livello di sottomodulo ...


1
Basta usare${maven.multiModuleProjectDirectory}
qoomon

Risposte:


164

Prova a impostare una proprietà in ogni pom per trovare la directory principale del progetto.

Nel genitore:

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

Nei bambini:

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

Nei nipoti:

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

19
Queste proprietà preimpostate sono state rimosse? ${parent.basedir}non analizza più nulla in 3.0.4 ...
matt5784

7
Sì, questo non funziona. $ {project.parent.basedir} restituisce null.
Jared

22
Ho avuto successo con, ${project.basedir}/..ma funziona davvero solo in progetti multi-modulo che si trovano in una rigida gerarchia di directory.
Jonathan

90
Sospiro. Incredibile, che Maven lo renda così difficile.
Stefan Haberl

5
Come Jonathan sopra, devo usare percorsi relativi, ma sento che è meglio usare la file.separatorvariabile in questo modo<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired

29

Almeno nella versione corrente di Maven (3.6.0) puoi usare ${maven.multiModuleProjectDirectory}


2
Cercando di trovare un documento su questo e sembra che questo sia inteso come un utilizzo interno, potrebbe essere rimosso / modificato in futuro MNG-6589
Greg Domjan

Usalo come? -1
hey_you

È una proprietà che puoi utilizzare come faresti con gli altri.
qoomon

non sono sicuro che dovremmo usare questa risposta. Secondo questo biglietto è interno e potrebbe andare in qualsiasi momento. Questo è anche il motivo per cui non è documentato da nessuna parte. Ancora nessuna soluzione pulita
Hilikus il

21

Usa directory-maven-plugin con directory-of goal .

A differenza di altri suggerimenti:

  • Questa soluzione funziona per progetti multi-modulo.
  • Funziona sia che tu costruisca l'intero progetto o un sottomodulo.
  • Funziona sia che esegui Maven dalla cartella principale o da un sottomodulo.
  • Non è necessario impostare una proprietà del percorso relativo in ogni sottomodulo!

Il plugin ti consente di impostare una proprietà di tua scelta sul percorso assoluto di uno qualsiasi dei moduli del progetto. Nel mio caso l'ho impostato sul modulo root ... Nel mio progetto 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>

Da quel momento in poi, $ {myproject.basedir} in qualsiasi sottomodulo pom ha sempre il percorso del modulo radice del progetto. E, naturalmente, puoi impostare la proprietà su qualsiasi modulo, non solo sulla radice ...


Non mettere "test" per la fase. Mi ha causato una serie di problemi. Funziona alla grande come mostrato sopra.
ElectronicBlacksmith

15

Ho trovato una soluzione per risolvere il mio problema: cerco i file delle proprietà utilizzando il plugin Groovy Maven.

Poiché il mio file delle proprietà è necessariamente nella directory corrente, in ../ o in .. / .., ho scritto un piccolo codice Groovy che controlla queste tre cartelle.

Ecco l'estratto del mio 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>

Funziona, ma non mi piace molto.

Quindi, se hai una soluzione migliore, non esitare a postare!


12

Quindi il problema come vedo è che non puoi ottenere il percorso assoluto di una directory padre in Maven.

<rant> Ho sentito parlare di questo come un anti-pattern , ma per ogni anti-pattern c'è un caso d'uso reale e legittimo per questo, e sono stufo di Maven che mi dice che posso solo seguire i loro schemi. </ rant>

Quindi il lavoro che ho trovato è stato usare antrun. Prova questo nel bambino 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>

Se corri mvn verifydovresti vedere qualcosa del genere:

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

Puoi quindi usarlo ${main.basedir}in uno qualsiasi degli altri plugin, ecc. Mi ci è voluto un po 'per capirlo, quindi spero che aiuti qualcun altro.


come lo trasmetto a maven-surefire-plugin?
Kalpesh Soni,

7

Un'altra alternativa:

nel pom genitore, usa:

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

Nei poms bambini, puoi fare riferimento a questa variabile.

Avvertenza principale: ti costringe a eseguire sempre il comando dalla directory pom principale principale. Quindi, se vuoi eseguire comandi (test ad esempio) solo per qualche modulo specifico, usa questa sintassi:

mvn test --projects

La configurazione di surefire per parametizzare una variabile "path_to_test_data" può quindi essere:

<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

Il seguente piccolo profilo ha funzionato per me. Avevo bisogno di una tale configurazione per CheckStyle, che ho inserito nella configdirectory nella radice del progetto, in modo da poterla eseguire dal modulo principale e dai sottomoduli.

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

Non funzionerà per i moduli nidificati, ma sono sicuro che può essere modificato per questo utilizzando diversi profili con differenti exists. (Non ho idea del motivo per cui dovrebbe esserci "../ .." nel tag di verifica e solo ".." nella proprietà sovrascritta stessa, ma funziona solo in questo modo.)


Non so perché funzioni (l'extra ../) ma questa sembra la soluzione più pulita (anch'io avevo problemi con la configurazione checkstyle.xml)
RockMeetHardplace

5

Nel mio caso funziona così:

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

Ho trovato una soluzione per risolvere questo problema: usa $ {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
Questo potrebbe non essere sempre sicuro; $ {parent.relativePath} può includere un nome di file, ad esempio "../pom.xml"
pimlottc

3

Sei nel progetto C, il progetto C è il sottomodulo di B e B è il sottomodulo di A. Prova a raggiungere la src/test/config/etcdirectory del modulo D dal progetto C. D è anche il sottomodulo di A. La seguente espressione rende possibile ottenere il percorso dell'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

In una risposta a un'altra domanda ho mostrato come il plug-in di proprietà-maven potrebbe essere esteso per utilizzare descrittori di proprietà esterni definiti nelle dipendenze di Maven.

È possibile estendere questa idea per avere più jar descrittori, ciascuno con il nome dell'ambiente come parte di artifactId, contenente un $ {env} .properties. Quindi è possibile utilizzare la proprietà per selezionare il file jar e delle proprietà appropriato, ad esempio:

<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

Ho appena migliorato lo script groovy dall'alto per scrivere la proprietà nel file delle proprietà padre principale:

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

Penso che se usi il modello di estensione usato nell'esempio per il plugin findbugs e il multimodulo potresti essere in grado di impostare le proprietà globali relative ai percorsi assoluti. Usa un top

esempio per multi modulo

Il pom di primo livello ha un progetto build-config non correlato e un'app-parent per i moduli del progetto multimodule. L'app-parent usa l'estensione per collegarsi al progetto build-config e ottenere risorse da esso. Viene utilizzato per trasportare i file di configurazione comuni ai moduli. Potrebbe anche essere un condotto per le proprietà. È possibile scrivere la directory principale in un file delle proprietà utilizzato dal build-config. (sembra troppo complesso)

Il problema è che è necessario aggiungere un nuovo livello superiore al progetto multimodulo per fare in modo che funzioni. Ho provato a fare un passo indietro con un progetto di configurazione di compilazione davvero non correlato, ma era complicato e sembrava fragile.


0

Questo estende la risposta di romaintaz, che è fantastica in quanto risolve il problema e sottolinea anche chiaramente la funzionalità mancante di Maven. Ho scelto una versione successiva del plug-in e ho aggiunto il caso in cui il progetto potrebbe essere profondo più di 3 livelli.

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

Ho scelto di non utilizzare una proprietà per definire il nome del file. Nota se build.properties non viene trovato, girerà per sempre. Ho aggiunto un rilevamento .git dir, ma non volevo complicare eccessivamente la risposta, quindi non è mostrato qui.

  <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

Avevo bisogno di risolvere un problema simile per il repository locale inserito nel progetto principale del progetto multi-modulo. Essenzialmente il vero percorso era ${basedir}/ lib. Alla fine ho deciso su questo nel mio parent.pom:

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

Questo basedirmostra sempre l'attuale modulo locale, non c'è modo di ottenere il percorso del progetto "principale" (vergogna di Maven). Alcuni dei miei sottomoduli sono una direzione più profonda, alcuni sono due direzioni più profonde, ma tutti sono sottomoduli diretti del genitore che definisce l'URL del repository.

Quindi questo non risolve il problema in generale. Puoi sempre combinarlo con la risposta accettata di Clay e definire qualche altra proprietà - funziona bene e deve essere ridefinito solo per i casi in cui il valore daparent.pom non è abbastanza buono. Oppure puoi semplicemente riconfigurare il plugin, cosa che fai solo negli artefatti POM (genitori di altri sottomoduli). Il valore estratto nella proprietà è probabilmente migliore se ne hai bisogno in più posti, specialmente quando non cambia nulla nella configurazione del plugin.

L'utilizzo basedirdel valore era la parte essenziale qui, perché l'URL file://${project.parent.relativePath}/libnon voleva fare il trucco (ho rimosso una barra per renderlo relativo). Usare una proprietà che mi dà un buon percorso assoluto e quindi andare relativo da esso era necessario.

Quando il percorso non è URL / URI, probabilmente non è un problema da eliminare basedir.


0

Ho effettuato l'accesso alla directory sopra usando $ {basedir} .. \ src \


1
si ma no. Per il sub-module1, punterà sulla directory di module2, non su main-project.
Romain Linsolas

-1

Hai provato ../../env_${env}.properties?

Normalmente facciamo quanto segue quando module2 è allo stesso livello dei sottomoduli

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

Penso che il ../ .. ti farebbe saltare di due livelli. In caso contrario, potresti contattare gli autori del plug-in e vedere se si tratta di un problema noto.


Se metto ../../env.props nel pom.xml principale, allora riceverò un errore quando Maven2 proverà a costruire il pom principale e tutto il moduleX. Questa configurazione infatti funzionerà solo per tutti i sottomoduli ...
Romain Linsolas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.