Propriété Maven2 qui indique le répertoire parent

105

J'ai un projet multi-modules, comme celui-ci:

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

J'ai besoin de définir un ensemble de propriétés (qui dépendent de l'environnement sur lequel je souhaite publier mon projet) dans Maven2. Je n'utiliserai pas <properties>car il y a beaucoup de propriétés ... Ainsi, j'utilise le plugin Properties Maven2 .

Les fichiers de propriétés se trouvent dans le main-project/répertoire. Comment puis-je définir le bon répertoire dans le pom.xml principal, afin de spécifier à tous les enfants où trouver le fichier de propriétés?

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

Si je mets seulement <file>env_${env}.properties</file>, alors quand Maven2 compile le premier module, il ne trouvera pas le main-project/env_dev.propertiesfichier. Si je définis <file>../env_${env}.properties</file>, une erreur sera générée au niveau du parent, ou à n'importe quel niveau de sous-module ...

Romain Linsolas
la source
1
Juste utiliser${maven.multiModuleProjectDirectory}
qoomon

Réponses:

164

Essayez de définir une propriété dans chaque pom pour trouver le répertoire principal du projet.

Chez le parent:

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

Chez les enfants:

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

Chez les petits-enfants:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>
Argile
la source
19
Ces propriétés prédéfinies ont-elles été supprimées? ${parent.basedir}ne analyse plus rien dans la version 3.0.4 ...
matt5784
7
Ouais, ça ne marche pas. $ {project.parent.basedir} prend la valeur null.
Jared
22
J'ai eu du succès avec, ${project.basedir}/..mais cela ne fonctionne vraiment que dans les projets multi-modules qui sont dans une hiérarchie de répertoires stricte.
Jonathan
90
Soupir. Incroyable, que Maven rend cela si difficile.
Stefan Haberl
5
Comme Jonathan ci-dessus, je dois utiliser des chemins relatifs, mais je pense qu'il est préférable d'utiliser la file.separatorvariable comme ceci<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired
29

Au moins dans la version actuelle de maven (3.6.0), vous pouvez utiliser ${maven.multiModuleProjectDirectory}

qoomon
la source
2
Essayer de trouver un document à ce sujet et il semble que cela soit destiné à un usage interne, peut être supprimé / modifié dans le futur MNG-6589
Greg Domjan
Utilisez-le comment? -1
hey_you
C'est une propriété que vous pouvez utiliser comme vous le feriez avec les autres.
qoomon le
je ne suis pas sûr que nous devrions utiliser cette réponse. Selon ce ticket, il est interne et peut partir à tout moment. C'est aussi pourquoi il n'est documenté nulle part. Toujours pas de solution propre
Hilikus
21

Utilisez directory-maven-plugin avec le but directory-of .

Contrairement à d'autres suggestions:

  • Cette solution fonctionne pour les projets multi-modules.
  • Cela fonctionne que vous construisiez l'ensemble du projet ou un sous-module.
  • Cela fonctionne que vous exécutiez maven à partir du dossier racine ou d'un sous-module.
  • Il n'est pas nécessaire de définir une propriété de chemin relatif dans chaque sous-module!

Le plugin vous permet de définir une propriété de votre choix sur le chemin absolu de l'un des modules du projet. Dans mon cas, je l'ai défini sur le module racine ... Dans mon projet 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>

Dès lors, $ {myproject.basedir} dans tout sous-module pom a toujours le chemin du module racine du projet. Et bien sûr, vous pouvez définir la propriété sur n'importe quel module, pas seulement la racine ...

sparkyd
la source
Ne mettez pas de «test» pour la phase. M'a causé une variété de problèmes. Fonctionne très bien comme indiqué ci-dessus.
ElectronicBlacksmith
15

J'ai trouvé une solution pour résoudre mon problème: je recherche les fichiers de propriétés à l'aide du plugin Groovy Maven.

Comme mon fichier de propriétés est forcément dans le répertoire courant, en ../ ou en .. / .., j'ai écrit un petit code Groovy qui vérifie ces trois dossiers.

Voici l'extrait de mon 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>

Cela fonctionne, mais je n'aime pas vraiment ça.

Alors, si vous avez une meilleure solution, n'hésitez pas à poster!

Romain Linsolas
la source
12

Donc, le problème que je vois est que vous ne pouvez pas obtenir le chemin absolu vers un répertoire parent dans maven.

<rant> J'ai entendu parler de cela comme d'un anti-modèle , mais pour chaque anti-modèle, il existe un cas d'utilisation réel et légitime, et j'en ai marre des maven qui me disent que je ne peux que suivre leurs modèles. </ diatribe>

Donc le travail autour que j'ai trouvé était d'utiliser antrun. Essayez ceci dans le fichier enfant 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>

Si vous exécutez, mvn verifyvous devriez voir quelque chose comme ceci:

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

Vous pouvez ensuite utiliser ${main.basedir}n'importe lequel des autres plugins, etc. Il m'a fallu un certain temps pour comprendre cela, alors j'espère que cela aidera quelqu'un d'autre.

Jared
la source
comment le transmettre à maven-surefire-plugin?
Kalpesh Soni
7

Une autre alternative:

dans le pom parent, utilisez:

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

Dans les enfants poms, vous pouvez référencer cette variable.

Mise en garde principale: cela vous oblige à toujours exécuter la commande à partir du répertoire pom parent principal. Ensuite, si vous souhaitez exécuter des commandes (test par exemple) uniquement pour un module spécifique, utilisez cette syntaxe:

test mvn - projets

La configuration de surefire pour paramétrer une variable "path_to_test_data" peut alors être:

<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>
François Marot
la source
5

Le petit profil suivant a fonctionné pour moi. J'avais besoin d'une telle configuration pour CheckStyle, que j'ai placée dans le configrépertoire à la racine du projet, afin de pouvoir l'exécuter à partir du module principal et des sous-modules.

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

Cela ne fonctionnera pas pour les modules imbriqués, mais je suis sûr qu'il peut être modifié pour cela en utilisant plusieurs profils avec existsdes s différents . (Je ne sais pas pourquoi il devrait y avoir "../ .." dans la balise de vérification et juste ".." dans la propriété overriden elle-même, mais cela ne fonctionne que de cette manière.)

Vic
la source
Je ne sais pas pourquoi cela fonctionne (le supplément ../) mais cela semble être la solution la plus propre (moi aussi j'avais des problèmes avec la configuration checkstyle.xml)
RockMeetHardplace
5

Dans mon cas, cela fonctionne comme ceci:

...
<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
la source
3

J'ai trouvé une solution pour résoudre ce problème: utilisez $ {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
la source
2
Cela peut ne pas toujours être sûr; $ {parent.relativePath} peut inclure un nom de fichier, par exemple "../pom.xml"
pimlottc
3

Vous êtes dans le projet C, le projet C est un sous-module de B et B est un sous-module de A. Vous essayez d'accéder au src/test/config/etcrépertoire du module D à partir du projet C.D est également un sous-module de A. L'expression suivante permet d'obtenir le chemin URI:

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

la source
1

Dans une réponse à une autre question j'ai montré comment l'extension maven-properties-plugin pouvait être étendue pour utiliser des descripteurs de propriété externes définis dans les dépendances Maven.

Vous pouvez étendre cette idée pour avoir plusieurs fichiers JAR descripteurs, chacun avec le nom de l'environnement faisant partie de artifactId, contenant un $ {env} .properties. Ensuite, vous pouvez utiliser la propriété pour sélectionner le fichier jar et propriétés approprié, par exemple:

<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>
Vendeur riche
la source
1

Je viens d'améliorer le script groovy ci-dessus pour écrire la propriété dans le fichier de propriétés parent racine:

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
la source
0

Je pense que si vous utilisez le modèle d'extension utilisé dans l'exemple pour le plugin findbugs & multimodule, vous pourrez peut-être définir des propriétés globales liées aux chemins absolus. Il utilise un haut

exemple pour multi module

Le pom de niveau supérieur a un projet build-config indépendant et un parent d'application pour les modules du projet multimodule. L'app-parent utilise l'extension pour se lier au projet build-config et en obtenir des ressources. Ceci est utilisé pour transporter les fichiers de configuration communs vers les modules. Cela peut également être un canal pour les propriétés. Vous pouvez écrire le répertoire supérieur dans un fichier de propriétés consommé par build-config. (cela semble trop complexe)

Le problème est qu'un nouveau niveau supérieur doit être ajouté au projet multi-module pour que cela fonctionne. J'ai essayé de m'éloigner d'un projet de configuration de construction vraiment sans rapport, mais il était baveux et semblait fragile.

Peter Kahn
la source
0

Cela étend la réponse de romaintaz, qui est géniale en ce qu'elle résout le problème et souligne également clairement la fonctionnalité manquante de maven. J'ai choisi une version ultérieure du plugin et ajouté le cas où le projet pouvait avoir plus de 3 niveaux de profondeur.

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

J'ai choisi de ne pas utiliser de propriété pour définir le nom de fichier. Notez que si le build.properties n'est pas trouvé, cela tournera pour toujours. J'ai ajouté une détection de répertoire .git, mais je ne voulais pas trop compliquer la réponse afin qu'elle ne soit pas affichée ici.

  <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
la source
0

J'avais besoin de résoudre un problème similaire pour le référentiel local placé dans le projet principal du projet multi-module. Essentiellement, le vrai chemin était ${basedir}/ lib. Enfin, j'ai réglé cela dans mon parent.pom:

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

Cela basedirmontre toujours au module local actuel, il n'y a aucun moyen d'obtenir le chemin vers le projet "maître" (la honte de Maven). Certains de mes sous-modules sont un répertoire plus profond, certains sont deux répertoires plus profonds, mais tous sont des sous - modules directs du parent qui définit l'URL du dépôt.

Cela ne résout donc pas le problème en général. Vous pouvez toujours le combiner avec la réponse acceptée de Clay et définir une autre propriété - fonctionne bien et doit être redéfini uniquement pour les cas où la valeur deparent.pom n'est pas assez bonne. Ou vous pouvez simplement reconfigurer le plugin - ce que vous ne faites que dans les artefacts POM (parents d'autres sous-modules). La valeur extraite dans la propriété est probablement meilleure si vous en avez besoin à plus d'endroits, en particulier lorsque rien dans la configuration du plugin ne change.

Utiliser basedirdans la valeur était la partie essentielle ici, car l'URL file://${project.parent.relativePath}/libne voulait pas faire l'affaire (j'ai supprimé une barre oblique pour la rendre relative). Utiliser une propriété qui me donne un bon chemin absolu, puis en sortir relatif était nécessaire.

Lorsque le chemin n'est pas une URL / URI, ce n'est probablement pas un problème à supprimer basedir.

virgo47
la source
0

J'ai accédé au répertoire ci-dessus en utilisant $ {basedir} .. \ src \

Secelean Monica
la source
1
Oui mais non. Pour le sub-module1, il pointera sur le répertoire de module2, pas sur le main-project.
Romain Linsolas
-1

Avez-vous essayé ../../env_${env}.properties?

Normalement, nous faisons ce qui suit lorsque module2 est au même niveau que les sous-modules

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

Je pense que le ../ .. vous permettrait de monter de deux niveaux. Sinon, vous pouvez contacter les auteurs du plug-in et voir s'il s'agit d'un problème connu.

sal
la source
Si je mets ../../env.props dans le pom.xml principal, alors j'obtiendrai une erreur lorsque Maven2 essaiera de construire le pom principal, et tout moduleX. Cette configuration ne fonctionnera en fait que pour tous les sous-modules ...
Romain Linsolas