Propiedad de Maven2 que indica el directorio principal

105

Tengo un proyecto de varios módulos, como este:

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

Necesito definir un conjunto de propiedades (que dependen del entorno en el que quiero lanzar mi proyecto) en Maven2. No lo usaré<properties> porque hay muchas propiedades ... Por lo tanto, uso el complemento Propiedades Maven2 .

Los archivos de propiedades se encuentran en el main-project/directorio. ¿Cómo puedo configurar el directorio correcto en el pom.xml principal, para especificar a los niños dónde encontrar el archivo de propiedades?

<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 solo configuro <file>env_${env}.properties</file>, cuando Maven2 compile el primer módulo, no encontrará el main-project/env_dev.propertiesarchivo. Si lo configuro <file>../env_${env}.properties</file>, se generará un error en el nivel principal o en cualquier nivel de submódulo ...

Romain Linsolas
fuente
1
Solo use${maven.multiModuleProjectDirectory}
qoomon

Respuestas:

164

Intente establecer una propiedad en cada pom para encontrar el directorio principal del proyecto.

En el padre:

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

En los niños:

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

En los nietos:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>
Arcilla
fuente
19
¿Se eliminaron estas propiedades preestablecidas? ${parent.basedir}ya no analiza nada en 3.0.4 ...
matt5784
7
Sí, esto no funciona. $ {project.parent.basedir} se evalúa como nulo.
Jared
22
He tenido éxito con ${project.basedir}/..pero eso realmente solo funciona en proyectos de múltiples módulos que están en una jerarquía de directorios estricta.
Jonathan
90
Suspiro. Increíble, que Maven lo haga tan difícil.
Stefan Haberl
5
Como Jonathan arriba, tengo que usar rutas relativas, pero siento que es mejor usar la file.separatorvariable de esta manera<main.basedir>${project.basedir}${file.separator}..</main.basedir>
Enwired
29

Al menos en la versión actual de maven (3.6.0) puede hacer uso de ${maven.multiModuleProjectDirectory}

qoomon
fuente
2
Intentando encontrar un documento sobre esto y parece que está destinado a un uso interno, puede eliminarse / cambiarse en el futuro MNG-6589
Greg Domjan
¿Cómo utilizarlo? -1
hey_you
Es una propiedad que puede usar como lo haría con los demás.
qoomon
No estoy seguro de que debamos usar esta respuesta. Según este ticket es interno y puede salir en cualquier momento. También es por eso que no está documentado en ninguna parte. Todavía no hay una solución limpia
Hilikus
21

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

A diferencia de otras sugerencias:

  • Esta solución funciona para proyectos de varios módulos.
  • Funciona tanto si construye el proyecto completo como un submódulo.
  • Funciona tanto si ejecuta maven desde la carpeta raíz como desde un submódulo.
  • ¡No es necesario establecer una propiedad de ruta relativa en todos y cada uno de los submódulos!

El complemento le permite establecer una propiedad de su elección en la ruta absoluta de cualquiera de los módulos del proyecto. En mi caso, lo configuré en el módulo raíz ... En mi proyecto 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>

A partir de entonces, $ {myproject.basedir} en cualquier submódulo pom siempre tiene la ruta del módulo raíz del proyecto. Y, por supuesto, puede establecer la propiedad en cualquier módulo, no solo en la raíz ...

Sparkyd
fuente
No ponga "prueba" para la fase. Me causó una variedad de problemas. Funciona muy bien como se muestra arriba.
ElectronicBlacksmith
15

Encontré una solución para resolver mi problema: busco los archivos de propiedades usando el complemento Groovy Maven.

Como mi archivo de propiedades está necesariamente en el directorio actual, en ../ o en .. / .., escribí un pequeño código Groovy que verifica estas tres carpetas.

Aquí está el extracto de mi 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>

Esto está funcionando, pero realmente no me gusta.

Entonces, si tienes una mejor solución, ¡no dudes en publicarla!

Romain Linsolas
fuente
12

Entonces, el problema, tal como lo veo, es que no puede obtener la ruta absoluta a un directorio principal en maven.

<rant> He oído hablar de esto como un antipatrón , pero para cada antipatrón hay un caso de uso real y legítimo, y estoy harto de que Maven me diga que solo puedo seguir sus patrones. </ despotricar>

Entonces, el trabajo que encontré fue usar antrun. Pruebe esto en el niño 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 ejecuta mvn verify, debería ver algo como esto:

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

Luego puede usarlo ${main.basedir}en cualquiera de los otros complementos, etc. Me tomó un tiempo resolver esto, así que espero que ayude a alguien más.

Jared
fuente
¿Cómo lo paso a maven-surefire-plugin?
Kalpesh Soni
7

Otra alternativa:

en el pom principal, use:

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

En los niños poms, puede hacer referencia a esta variable.

Advertencia principal: le obliga a ejecutar siempre el comando desde el directorio pom padre principal. Luego, si desea ejecutar comandos (prueba, por ejemplo) solo para algún módulo específico, use esta sintaxis:

prueba mvn --proyectos

La configuración de surefire para parametizar una variable "path_to_test_data" puede ser entonces:

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

El siguiente pequeño perfil funcionó para mí. Necesitaba una configuración de este tipo para CheckStyle, que puse en el configdirectorio en la raíz del proyecto, para poder ejecutarla desde el módulo principal y desde los submódulos.

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

No funcionará para módulos anidados, pero estoy seguro de que se puede modificar para eso usando varios perfiles con diferentes exists. (No tengo idea de por qué debería haber "../ .." en la etiqueta de verificación y solo ".." en la propiedad anulada, pero solo funciona de esa manera).

Vic
fuente
No sé por qué funciona esto (el extra ../) pero esta parece ser la solución más limpia (yo también estaba teniendo problemas con la configuración checkstyle.xml)
RockMeetHardplace
5

En mi caso funciona así:

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

Encontré una solución para resolver este problema: use $ {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
fuente
2
Es posible que esto no siempre sea seguro; $ {parent.relativePath} puede incluir un nombre de archivo, por ejemplo, "../pom.xml"
pimlottc
3

Usted está en el proyecto C, el proyecto C es un submódulo de B y B es un submódulo de A. Intenta llegar al src/test/config/etcdirectorio del módulo D desde el proyecto C. D también es un submódulo de A. La siguiente expresión hace posible obtener la ruta URI:

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

fuente
1

En una respuesta a otra pregunta , mostré cómo el complemento de propiedades de maven podría extenderse para usar descriptores de propiedad externos definidos en las dependencias de Maven.

Puede ampliar esa idea para tener varios archivos jar de descriptor, cada uno con el nombre del entorno como parte del artifactId, que contiene un $ {env} .properties. Luego, puede usar la propiedad para seleccionar el archivo jar y de propiedades apropiado, por ejemplo:

<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>
Vendedor rico
fuente
1

Acabo de mejorar el script maravilloso de arriba para escribir la propiedad en el archivo de propiedades raíz principal:

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

Creo que si usa el patrón de extensión utilizado en el ejemplo para el complemento y multimódulo findbugs, es posible que pueda establecer propiedades globales relacionadas con rutas absolutas. Usa un top

ejemplo de módulo múltiple

El pom de nivel superior tiene un proyecto build-config no relacionado y una aplicación principal para los módulos del proyecto multimódulo. El padre de la aplicación usa la extensión para vincularse al proyecto build-config y obtener recursos de él. Se utiliza para llevar archivos de configuración comunes a los módulos. También puede ser un conducto para las propiedades. Puede escribir el directorio superior en un archivo de propiedades consumido por build-config. (parece demasiado complejo)

El problema es que se debe agregar un nuevo nivel superior al proyecto de varios módulos para que esto funcione. Intenté dar un paso al lado de un proyecto de configuración de compilación realmente no relacionado, pero era torpe y parecía frágil.

Peter Kahn
fuente
0

Esto amplía la respuesta de romaintaz, que es increíble porque resuelve el problema y también señala claramente la funcionalidad que falta de maven. Recogí una versión posterior del complemento y agregué el caso en el que el proyecto podría tener más de 3 niveles de profundidad.

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

Elegí no usar una propiedad para definir el nombre del archivo. Tenga en cuenta que si no se encuentra build.properties, esto girará para siempre. Agregué una detección de directorio .git, pero no quería complicar demasiado la respuesta, por lo que no se muestra aquí.

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

Necesitaba resolver un problema similar para el repositorio local ubicado en el proyecto principal del proyecto de varios módulos. Básicamente, la ruta real era ${basedir}/ lib. Finalmente me decidí por esto en mi parent.pom:

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

Eso basedirsiempre muestra el módulo local actual, no hay forma de obtener la ruta al proyecto "maestro" (la vergüenza de Maven). Algunos de mis submódulos son un directorio más profundo, algunos son dos directorios más profundos, pero todos son submódulos directos del padre que define la URL del repositorio.

Entonces esto no resuelve el problema en general. Siempre puede combinarlo con la respuesta aceptada de Clay y definir alguna otra propiedad: funciona bien y debe redefinirse solo para los casos en que el valor de parent.pomno es lo suficientemente bueno. O simplemente puede reconfigurar el complemento, lo que hace solo en los artefactos POM (padres de otros submódulos). El valor extraído en la propiedad probablemente sea mejor si lo necesita en más lugares, especialmente cuando no cambia nada en la configuración del complemento.

Usar basedirel valor fue la parte esencial aquí, porque la URL file://${project.parent.relativePath}/libno quería hacer el truco (eliminé una barra para hacerla relativa). Usar la propiedad que me da una buena ruta absoluta y luego ir relativa a ella era necesario.

Cuando la ruta no es URL / URI, probablemente no sea un problema descartarla basedir.

virgo47
fuente
0

Accedí al directorio anterior usando $ {basedir} .. \ src \

Monica Secelean
fuente
1
si pero no. Para el sub-module1, apuntará al directorio de module2, no al main-project.
Romain Linsolas
-1

Lo intentaste ../../env_${env}.properties?

Normalmente hacemos lo siguiente cuando module2 está en el mismo nivel que los submódulos

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

Creo que el ../ .. te permitiría saltar dos niveles. De lo contrario, es posible que desee ponerse en contacto con los autores del complemento y ver si se trata de un problema conocido.

sal
fuente
Si pongo ../../env.props en el pom.xml principal, obtendré un error cuando Maven2 intente construir el pom principal y todos los moduleX. De hecho, esta configuración solo funciona para todos los submódulos ...
Romain Linsolas