Maven2-Eigenschaft, die das übergeordnete Verzeichnis angibt

105

Ich habe ein Multi-Modul-Projekt wie dieses:

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

Ich muss in Maven2 eine Reihe von Eigenschaften definieren (die von der Umgebung abhängen, von der ich mein Projekt freigeben möchte). Ich werde nicht verwenden, <properties>da es viele Eigenschaften gibt ... Daher verwende ich das Eigenschaften Maven2-Plugin .

Die Eigenschaftendateien befinden sich im main-project/Verzeichnis. Wie kann ich das richtige Verzeichnis in der Hauptdatei pom.xml festlegen, um allen untergeordneten Elementen anzugeben, wo sich die Eigenschaftendatei befindet?

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

Wenn ich nur setze <file>env_${env}.properties</file>, findet Maven2 beim Kompilieren des ersten Moduls die main-project/env_dev.propertiesDatei nicht. Wenn ich einstelle <file>../env_${env}.properties</file>, wird ein Fehler auf der übergeordneten Ebene oder auf einer beliebigen Untermodulebene ausgelöst ...

Romain Linsolas
quelle
1
Verwenden ${maven.multiModuleProjectDirectory}
Sie

Antworten:

164

Versuchen Sie, in jedem POM eine Eigenschaft festzulegen, um das Hauptprojektverzeichnis zu finden.

Im Elternteil:

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

Bei den Kindern:

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

Bei den Enkelkindern:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>
Lehm
quelle
19
Wurden diese voreingestellten Eigenschaften entfernt? ${parent.basedir}analysiert nicht mehr in irgendetwas in 3.0.4 ...
matt5784
7
Ja, das funktioniert nicht. $ {project.parent.basedir} wird mit null ausgewertet.
Jared
22
Ich hatte Erfolg damit, ${project.basedir}/..aber das funktioniert wirklich nur in Projekten mit mehreren Modulen, die sich in einer strengen Verzeichnishierarchie befinden.
Jonathan
90
Seufzer. Unglaublich, dass Maven das so schwer macht.
Stefan Haberl
5
Wie Jonathan oben muss ich relative Pfade verwenden, aber ich file.separator<main.basedir>${project.basedir}${file.separator}..</main.basedir>
denke
29

Zumindest in der aktuellen Maven-Version (3.6.0) können Sie davon Gebrauch machen ${maven.multiModuleProjectDirectory}

Qoomon
quelle
2
Der Versuch, ein Dokument zu diesem Thema zu finden, und es scheint, dass dies als interne Verwendung gedacht ist, kann in Zukunft entfernt / geändert werden. MNG-6589
Greg Domjan
Nutzen Sie es wie? -1
hey_you
Es ist eine Eigenschaft, die Sie wie bei anderen verwenden können.
Qoomon
Ich bin mir nicht sicher, ob wir diese Antwort verwenden sollten. Laut diesem Ticket ist es intern und kann jederzeit gehen. Das ist auch der Grund, warum es nirgendwo dokumentiert ist. Immer noch keine saubere Lösung
Hilikus
21

Verwenden Sie das Verzeichnis-Maven-Plugin mit dem Verzeichnis des Ziels .

Im Gegensatz zu anderen Vorschlägen:

  • Diese Lösung funktioniert für Projekte mit mehreren Modulen.
  • Es funktioniert unabhängig davon, ob Sie das gesamte Projekt oder ein Untermodul erstellen.
  • Es funktioniert unabhängig davon, ob Sie maven aus dem Stammordner oder einem Submodul ausführen.
  • Es ist nicht erforderlich, in jedem Submodul eine relative Pfadeigenschaft festzulegen!

Mit dem Plugin können Sie eine Eigenschaft Ihrer Wahl auf den absoluten Pfad aller Module des Projekts festlegen. In meinem Fall habe ich es auf das Root-Modul gesetzt ... In meinem Projekt 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>

Von da an hat $ {myproject.basedir} in einem beliebigen Submodul pom immer den Pfad des Projektstammmoduls. Und natürlich können Sie die Eigenschaft auf jedes Modul festlegen, nicht nur auf das Root-Verzeichnis ...

sparkyd
quelle
Setzen Sie keinen "Test" für die Phase. Verursachte mir eine Vielzahl von Problemen. Funktioniert wie oben gezeigt.
ElectronicBlacksmith
15

Ich habe eine Lösung gefunden, um mein Problem zu lösen: Ich durchsuche die Eigenschaftendateien mit dem Groovy Maven-Plugin.

Da sich meine Eigenschaftendatei notwendigerweise im aktuellen Verzeichnis befindet, in ../ oder in .. / .., habe ich einen kleinen Groovy-Code geschrieben, der diese drei Ordner überprüft.

Hier ist der Auszug aus meiner 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>

Das funktioniert, aber ich mag es nicht wirklich.

Also, wenn Sie eine bessere Lösung haben, zögern Sie nicht zu posten!

Romain Linsolas
quelle
12

Aus meiner Sicht besteht das Problem darin, dass Sie den absoluten Pfad zu einem übergeordneten Verzeichnis in maven nicht erhalten können.

<rant> Ich habe gehört, dass dies als Anti-Muster bezeichnet wird , aber für jedes Anti-Muster gibt es einen echten, legitimen Anwendungsfall, und ich habe es satt, mir zu sagen, dass ich nur ihren Mustern folgen kann. </ schimpfen>

Die Arbeit, die ich fand, bestand darin, Antrun zu verwenden. Versuchen Sie dies in der untergeordneten Datei 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>

Wenn du rennst mvn verify, solltest du so etwas sehen:

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

Sie können es dann ${main.basedir}in jedem anderen Plugin usw. verwenden. Ich habe eine Weile gebraucht , um das herauszufinden, also hoffe, es hilft jemand anderem.

Jared
quelle
Wie gebe ich es an das Maven-Surefire-Plugin weiter?
Kalpesh Soni
7

Eine andere Alternative:

Verwenden Sie im übergeordneten POM:

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

In den Kinder-Poms können Sie auf diese Variable verweisen.

Haupteinschränkung: Sie werden gezwungen, den Befehl immer aus dem übergeordneten Haupt-POM-Verzeichnis auszuführen. Wenn Sie dann Befehle (z. B. Test) nur für ein bestimmtes Modul ausführen möchten, verwenden Sie diese Syntax:

MVN-Test - Projekte

Die Konfiguration von todsicher zur Parametisierung einer Variablen "path_to_test_data" kann dann sein:

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

Das folgende kleine Profil hat bei mir funktioniert. Ich brauchte eine solche Konfiguration für CheckStyle, die ich in das configVerzeichnis im Stammverzeichnis des Projekts gestellt habe, damit ich sie vom Hauptmodul und von den Submodulen ausführen kann.

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

Es funktioniert nicht für verschachtelte Module, aber ich bin sicher, dass es dafür mit mehreren Profilen mit unterschiedlichen geändert werden kann exists. (Ich habe keine Ahnung, warum das Verifizierungs-Tag "../ .." und in der überschriebenen Eigenschaft selbst nur ".." enthalten sollte, aber es funktioniert nur auf diese Weise.)

Vic
quelle
Ich weiß nicht, warum das funktioniert (das Extra ../), aber dies scheint die sauberste Lösung zu sein (auch ich hatte Probleme mit der checkstyle.xml-Konfiguration)
RockMeetHardplace
5

In meinem Fall funktioniert es so:

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

Ich habe eine Lösung gefunden, um dieses Problem zu lösen: Verwenden Sie $ {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
quelle
2
Dies ist möglicherweise nicht immer sicher. $ {parent.relativePath} kann einen Dateinamen enthalten, z. B. "../pom.xml"
pimlottc
3

Sie befinden sich in Projekt C, Projekt C ist das Submodul von B und B ist das Submodul von A. Sie versuchen, das src/test/config/etcVerzeichnis von Modul D aus Projekt C zu erreichen . D ist auch das Submodul von A. Der folgende Ausdruck ermöglicht es, den URI-Pfad abzurufen:

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

quelle
1

In einer Antwort auf eine andere Frage habe ich gezeigt, wie das Maven-Properties-Plugin erweitert werden kann, um externe Eigenschaftsbeschreibungen zu verwenden, die in Maven-Abhängigkeiten definiert sind.

Sie können diese Idee auf mehrere Deskriptor-Jars erweitern, die jeweils den Umgebungsnamen als Teil der Artefakt-ID enthalten und eine $ {env} .properties enthalten. Anschließend können Sie mit der Eigenschaft die entsprechende JAR- und Eigenschaftendatei auswählen, z. B.:

<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>
Reicher Verkäufer
quelle
1

Ich verbessere nur das groovige Skript von oben, um die Eigenschaft in die übergeordnete Eigenschaftendatei zu schreiben:

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

Ich denke, wenn Sie das im Beispiel für Findbugs Plugin & Multimodule verwendete Erweiterungsmuster verwenden, können Sie möglicherweise globale Eigenschaften in Bezug auf absolute Pfade festlegen. Es verwendet ein Top

Beispiel für Multi-Modul

Das POM der obersten Ebene verfügt über ein nicht verwandtes Build-Konfigurationsprojekt und ein übergeordnetes App-Element für die Module des Multimodul-Projekts. Das übergeordnete App-Element verwendet die Erweiterung, um sich mit dem Build-Config-Projekt zu verknüpfen und Ressourcen daraus abzurufen. Dies wird verwendet, um allgemeine Konfigurationsdateien zu den Modulen zu übertragen. Es kann auch eine Leitung für Eigenschaften sein. Sie können das oberste Verzeichnis in eine Eigenschaftendatei schreiben, die von der Build-Konfiguration verwendet wird. (es scheint zu komplex)

Das Problem ist, dass dem Multi-Modul-Projekt eine neue oberste Ebene hinzugefügt werden muss, damit dies funktioniert. Ich habe versucht, mit einem wirklich unabhängigen Build-Config-Projekt Schritt zu halten, aber es war klobig und schien brüchig.

Peter Kahn
quelle
0

Dies erweitert die Antwort von romaintaz, was insofern fantastisch ist, als es das Problem löst und auch deutlich auf die fehlende Funktionalität von maven hinweist. Ich habe eine spätere Version des Plugins aufgegriffen und den Fall hinzugefügt, dass das Projekt mehr als 3 Ebenen tief sein könnte.

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

Ich habe beschlossen, keine Eigenschaft zum Definieren des Dateinamens zu verwenden. Beachten Sie, dass sich die Datei build.properties für immer dreht, wenn sie nicht gefunden wird. Ich habe eine .git-Verzeichniserkennung hinzugefügt, wollte die Antwort jedoch nicht zu komplizieren, sodass sie hier nicht angezeigt wird.

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

Ich musste ein ähnliches Problem für das lokale Repository lösen, das im Hauptprojekt des Multi-Modul-Projekts platziert war. Im Wesentlichen war der eigentliche Pfad ${basedir}/ lib. Schließlich entschied ich mich in meinem parent.pom:

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

Das basedirzeigt immer zum aktuellen lokalen Modul, es gibt keine Möglichkeit, den Weg zum "Master" -Projekt zu finden (Mavens Schande). Einige meiner Submodule sind ein Dir tiefer, andere zwei Dir tiefer, aber alle sind direkte Submodule des übergeordneten , das die Repo-URL definiert.

Dies löst das Problem also im Allgemeinen nicht. Sie können es jederzeit mit der von Clay akzeptierten Antwort kombinieren und eine andere Eigenschaft definieren - funktioniert einwandfrei und muss nur in Fällen neu definiert werden, in denen der Wert von parent.pomnicht gut genug ist. Oder Sie konfigurieren das Plugin einfach neu - was Sie nur bei POM-Artefakten (Eltern anderer Submodule) tun. Der in die Eigenschaft extrahierte Wert ist wahrscheinlich besser, wenn Sie ihn an mehreren Stellen benötigen, insbesondere wenn sich nichts in der Plugin-Konfiguration ändert.

Die Verwendung basedirim Wert war hier der wesentliche Teil, weil URLfile://${project.parent.relativePath}/lib den Trick nicht ausführen wollte (ich habe einen Schrägstrich entfernt, um ihn relativ zu machen). Es war notwendig, eine Eigenschaft zu verwenden, die mir einen guten absoluten Pfad gibt, und dann relativ dazu zu gehen.

Wenn der Pfad nicht URL / URI ist, ist es wahrscheinlich kein Problem, ihn zu löschen basedir.

Jungfrau47
quelle
0

Ich habe mit $ {basedir} .. \ src \ auf das obige Verzeichnis zugegriffen

Secelean Monica
quelle
1
Ja aber nein. Für das sub-module1wird es auf das Verzeichnis von zeigen module2, nicht auf das main-project.
Romain Linsolas
-1

Hast du es versucht ../../env_${env}.properties?

Normalerweise machen wir Folgendes, wenn sich Modul2 auf derselben Ebene wie die Untermodule befindet

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

Ich würde denken, das ../ .. würde dich zwei Ebenen hochspringen lassen. Wenn nicht, können Sie sich an die Autoren des Plug-Ins wenden und prüfen, ob dies ein bekanntes Problem ist.

sal
quelle
Wenn ich ../../env.props in die Haupt-pom.xml einfüge, wird eine Fehlermeldung angezeigt, wenn Maven2 versucht, die Haupt-pom und alle ModuleX zu erstellen. Diese Konfiguration funktioniert in der Tat nur für alle Untermodule ...
Romain Linsolas