Suchen des Stammverzeichnisses eines Maven-Reaktorprojekts mit mehreren Modulen

71

Ich möchte das Maven-Dependency-Plugin verwenden, um Artefakte aus allen Untermodulen meines Multi-Modul-Projekts in ein Verzeichnis zu kopieren, das relativ zum Stammverzeichnis des gesamten Projekts ist.

Das heißt, mein Layout sieht ähnlich aus, Namen geändert:

to-deploy/
my-project/
    module-a/
    module-b/
    more-modules-1/
        module-c/
        module-d/
    more-modules-2/
        module-e/
        module-f/
    ...

Und ich möchte, dass alle Artefakte aus den Zielverzeichnissen ihrer jeweiligen Module kopiert werden, my-project/../to-deploydamit ich am Ende mit

to-deploy/
    module-a.jar
    module-b.jar
    module-c.jar
    module-d.jar
    module-e.jar
    module-f.jar
my-project/
    ...

Ich könnte es mit einem relativen Pfad in jedem Modul machen, wie folgt:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy</id>
                    <phase>install</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>${project.groupId}</groupId>
                                <artifactId>${project.artifactId}</artifactId>
                                <version>${project.version}</version>
                                <type>jar</type>
                                <outputDirectory>../../to-deploy</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>

Aber ich möchte lieber keinen relativen Pfad im <outputDirectory>Element angeben . Ich würde so etwas bevorzugen ${reactor.root.directory}/../to-deploy, aber ich kann so etwas nicht finden.

Außerdem würde ich es vorziehen, wenn es eine Möglichkeit gäbe, diese Konfiguration des Maven-Abhängigkeits-Plugins zu erben, damit ich sie nicht für jedes Modul angeben muss.

Ich habe auch versucht, eine benutzerdefinierte Eigenschaft vom Root-POM zu erben:

<properties>
    <myproject.root>${basedir}</myproject.root>
</properties>

Aber wenn ich versuchte, ${myproject.root}in den Modul- ${basedir}POMs zu verwenden , würde sich das auf das basedir des Moduls auflösen.

Außerdem habe ich http://labs.consol.de/lang/de/blog/maven/project-root-path-in-a-maven-multi-module-project/ gefunden, wo vorgeschlagen wird, dass jeder Entwickler und vermutlich der kontinuierliche Der Integrationsserver sollte das Stammverzeichnis in einer Datei profile.xml konfigurieren, aber ich halte es nicht für eine Lösung.

Gibt es also eine einfache Möglichkeit, die Wurzel eines Projekts mit mehreren Modulen zu finden?

Christoffer Hammarström
quelle

Antworten:

43

Seit Maven 3.3.1 können Sie ${maven.multiModuleProjectDirectory}für diesen Zweck verwenden. (Dank an https://stackoverflow.com/a/48879554/302789 )

Bearbeiten: Dies scheint nur dann ordnungsgemäß zu funktionieren, wenn Sie einen .mvnOrdner im Stammverzeichnis Ihres Projekts haben.

Grégory Joseph
quelle
1
Könnten Sie dazu auf die Versionshinweise oder Dokumente verlinken? Ich kann sie nicht finden.
Christoffer Hammarström
2
@ ChristofferHammarström aus irgendeinem Grund, der nur in den Versionshinweisen von 3.3.9 als Fehlerbehebung angezeigt wird : maven.apache.org/docs/3.3.9/release-notes.html Aber weiter in Mavens Jira-Projekt graben, hier es wird eingeführt und ist in der Tat als fest für 3.3.1 markiert: issue.apache.org/jira/browse/MNG-5767
Grégory Joseph
2
Leider haben sie es "repariert" und jetzt zeigt es nur noch auf das aktuelle Teilprojekt, nicht auf die eigentliche Multiprojektwurzel. Es ist also nicht besser als die anderen Optionen.
Kaqqao
6
@kaqqao ja es ist seltsam. Ich kann nicht sagen, dass ich genau verstehe, was dieser Fehler meldet, aber wenn ich es versuche mvn help:evaluate -Dexpression=maven.multiModuleProjectDirectory, funktioniert es für mich ¯ \ _ (ツ) _ / ¯ edit: Ich habe festgestellt, dass es nur zu funktionieren scheint, wenn ich einen .mvnOrdner oben in meinem Projekt habe !
Grégory Joseph
2
Versucht mit Maven 3.6.3. Fazit: 1) Es muss einen .mvnOrdner geben, der jedoch leer sein kann. 2) mvn meldet das Stammverzeichnis für das gesamte Projekt ordnungsgemäß, selbst wenn der Befehl aus einem untergeordneten Verzeichnis (Modul) ausgeführt wird.
wlnirvana
71

verwenden ${session.executionRootDirectory}

Für die Aufzeichnung ${session.executionRootDirectory}funktioniert für mich in POM-Dateien in Maven 3.0.3. Diese Eigenschaft ist das Verzeichnis, in dem Sie ausgeführt werden. Führen Sie also das übergeordnete Projekt aus, und jedes Modul kann den Pfad zu diesem Stammverzeichnis abrufen.

Ich habe die Plugin-Konfiguration, die diese Eigenschaft verwendet, in das übergeordnete POM eingefügt, damit sie vererbt wird. Ich verwende es in einem Profil, das ich nur auswähle, wenn ich weiß, dass ich Maven für das übergeordnete Projekt ausführen werde. Auf diese Weise ist es weniger wahrscheinlich, dass ich diese Variable in unerwünschter Weise verwende, wenn ich Maven in einem untergeordneten Projekt ausführe (da die Variable dann nicht der Pfad zum übergeordneten Projekt ist).

Zum Beispiel,

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-artifact</id>
            <phase>package</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>${project.artifactId}</artifactId>
                        <version>${project.version}</version>
                        <type>${project.packaging}</type>
                    </artifactItem>
                </artifactItems>
                <outputDirectory>${session.executionRootDirectory}/target/</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
anonym
quelle
3
$ {session.executionRootDirectory} war auch für mich das Wundermittel. Warum ist das nicht in maven.apache.org/pom.html ?
Bruce Edge
Versuchen Sie es mit $ {project.basedir}, wenn andere Maven-Umgebungsvariablen wie $ {session.executionRootDirectory} nicht funktionieren.
Pradeeban Kathiravelu
7
Ich habe $ {session.executionRootDirectory} mit Maven 3.3.9 ausprobiert und es funktioniert nicht mehr. Sie müssen stattdessen $ {user.dir} verwenden. Meiner Meinung nach ist diese Option unbefriedigend, da ich nur das übergeordnete und nicht das Submodul unabhängig ausführen kann. Damit dies funktioniert, benötigen Sie diesen stackoverflow.com/questions/1012402/…
Dr4gon
24

In meinen Projekten habe ich die Eigenschaft in den Submodul-Poms überschrieben.

    root:           <myproject.root>${basedir}</myproject.root>
    moduleA:        <myproject.root>${basedir}/..</myproject.root>
    other/moduleX:  <myproject.root>${basedir}/../..</myproject.root>

Auf diese Weise haben Sie immer noch die relativen Pfade, aber Sie können ein Plugin einmal im Root-Modul definieren, und Ihre Module erben es mit der richtigen Ersetzung für myproject.root.

Karel Vervaeke
quelle
5
Wirst du all diese "/ .." und "/../ .." verwalten? Ich meine, sicher, dass diese Lösung funktioniert, aber sie verbirgt die tatsächliche Struktur Ihres Projekts.
Henry Aloni
Ich denke, das sollte die akzeptierte Antwort sein. Dies funktioniert sogar, wenn Sie nur ein einzelnes Modul erstellen.
Filip
Diese Lösung funktioniert bei Verwendung von Eclipse und m2e, da keine exotischen Plugins erforderlich sind.
3urdoch
1
Vielen Dank! Dies ist der eleganteste Weg für einfache Projekte. Keine zusätzlichen Plugins, nur explizite Überschreibung. +1
Nikolai Shevchenko
20

Es gibt ein Maven-Plugin, das dieses spezielle Problem löst: das Verzeichnis-Maven-Plugin

Der Stammpfad Ihres Projekts wird einer Eigenschaft Ihrer Wahl zugewiesen. Siehe highest-basedirZiel in den Dokumenten.

Zum Beispiel:

<!-- Directory plugin to find parent root directory absolute path -->
<plugin>
  <groupId>org.commonjava.maven.plugins</groupId>
  <artifactId>directory-maven-plugin</artifactId>
  <version>0.1</version>
  <executions>
    <execution>
      <id>directories</id>
      <goals>
        <goal>highest-basedir</goal>
      </goals>
      <phase>initialize</phase>
      <configuration>
        <property>main.basedir</property>
      </configuration>
    </execution>
  </executions>
</plugin>

Verwenden Sie dann ${main.basedir}irgendwo in Ihrer Eltern / Kind-Datei pom.xml.

Andrejs
quelle
3
Ich schlage vor, diese Lösung zu vermeiden : Wenn Sie die Phase nicht ausführen (im Beispiel ist initialize), wird die Eigenschaft nicht gelöst. Wenn Sie sie beispielsweise für ein Submodul in der clean/pre-cleanPhase benötigen, werden Sie feststellen , dass Sie die Phase duplizieren / hacken Konfiguration auf Submodulen (bereits in verschiedenen Projekten gesehen). Verwenden Sie die Lösung von @karel, es sei denn, Sie haben spezielle Anforderungen (und nein, Ihr Projekt ist nicht speziell).
Sergio
1
Dies ist eine gute Lösung. Für eine frühere Phase können Sie einfach angeben <phase>pre-clean</phase>.
Armandino
5

Wie andere vorgeschlagen haben, ist das Directory-Maven-Plugin der richtige Weg. Ich fand jedoch, dass es am besten mit dem Ziel "Verzeichnis von" funktioniert, wie hier beschrieben: https://stackoverflow.com/a/37965143/6498617 .

Ich bevorzuge dies, da die Verwendung von höchster Basis bei einem Multimodulprojekt mit verschachtelten Multimodul-Poms für mich nicht funktioniert hat. Mit dem Zielverzeichnis können Sie eine Eigenschaft für den Pfad eines Moduls im gesamten Projekt festlegen, einschließlich natürlich des Stammverzeichnisses. Es ist auch viel besser als $ {session.executionRootDirectory}, da es immer funktioniert, unabhängig davon, ob Sie das Root- oder ein Submodul erstellen, und unabhängig vom aktuellen Arbeitsverzeichnis, aus dem Sie mvn.

sparkyd
quelle
2

Ich habe ein ähnliches Problem festgestellt, als ich Dateien zwischen Projekten kopieren musste. Was Maven tut, ist logisch, da es die im Repository installierte Datei pom.xml von fest codierten Werten fernhält.

Meine Lösung bestand darin, kopiertes Verzeichnis in ein Maven-Artefakt einzufügen und dann Ant zum Extrahieren / Kopieren zu verwenden

M. Hoang
quelle
2

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
Wollen Sie damit sagen, dass das basedir $ {project.basedir} /../../ ist? Dies funktioniert nur, wenn Sie die untergeordneten Projekte an einer bestimmten Stelle im übergeordneten Projekt ablegen. Die Frage ist, wie man diesen Weg im Allgemeinen findet.
Djjeck
Die basedir ist `$ {} project.basedir /../ . Just some unique file is needed there (in my case it's checkstyle.xml ). And yes, this works (as I mentioned) for one-level of module nesting. Usually modules are put into subdirectories, so I don't consider here any other cases (but I'm sure something similar will work). The question was how to find something like $ {reactor.root.directory} . Here is my solution. But in my case I needed the / config` Ordner. Mit einer geringfügigen Änderung kann man auch das Stammverzeichnis erhalten. Und für verschachtelte Module existfunktionieren auch mehrere Profile mit unterschiedlichen .
Vic
Es gibt verschiedene Lösungen, aber ich wollte eine einfache finden, bei der nicht alle Module kopiert und eingefügt werden müssen.
Vic
1

Mir ist kein "netter" Weg bekannt, um die Wurzel eines Multi-Modul-Projekts zu finden. Aber Sie können vielleicht Ihren aktuellen Ansatz ein wenig verbessern.

Eine erste Alternative wäre, ein zusätzliches Modul direkt unter dem Stammprojekt zu erstellen, alle EARs als Abhängigkeiten darin zu deklarieren und dependency:copy-dependenciesdie Abhängigkeiten des Moduls to-deploy(relativ) in das Verzeichnis zu kopieren . Ja, der Pfad wäre immer noch relativ, aber da die Konfiguration des Abhängigkeits-Plugins zentralisiert wäre, finde ich das nicht so ärgerlich.

Eine zweite Alternative wäre, das verwenden Maven Assembly Plugin anstelle des Maven Dependency Plugin eine Verteilung mit dem erstellen dir Format (das eine Verteilung in einem Verzeichnis erstellen wird). Das würde ich eigentlich tun.

Pascal Thivent
quelle
1
Vielen Dank! Die Verwendung des Assembly-Plugins wäre am besten, wenn es nur möglich wäre, die Dokumente zu verstehen und sie mit dem Build-Lebenszyklus zu verknüpfen. Ich habe gerade eine Stunde damit verbracht, es zum Laufen zu bringen, und aufgegeben ...
Christoffer Hammarström
1

Eine andere Lösung wäre, eine Ant-Task zu verwenden, um "rootdir = $ {basedir}" in ein Ziel / root.properties im Root-Projekt zu schreiben, und dann das Eigenschaften-Plugin zu verwenden, um diese Datei wieder einzulesen. Ich habe es nicht versucht ich selbst, aber ich denke es sollte funktionieren ..?

neu242
quelle
3
Und woher wissen Sie den Speicherort dieser Datei aus der POM-Datei eines Moduls, auf das verwiesen wird? Wenn Sie den Speicherort dieser Datei kennen würden, müssten Sie den Inhalt nicht lesen.
Djjeck
Wenn Sie Git verwenden und Ant zum Aufrufen bringen, git rev-parse --show-toplevelkönnte dies einfach funktionieren.
Ed Randall
0

so dass: irgendwo in den Eigenschaften eines übergeordneten Projekts habe ich die Datei, die ich später beziehen muss, weshalb ich überall einen absoluten Pfad darauf brauche. Also, ich bekomme es mit Hilfe von groovy :

<properties>    
<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); 
          } 
        } 
        // setting path together with file name in variable xyz_format 
        project.properties['xyz_format'] =f.getAbsolutePath() 
                            + File.separator 
                            + "abc_format.xml"; 
</source>
</properties>   

und dann:

  <properties>
     <snapshots>http://localhost:8081/snapshots<snapshots>
     <releases>http://localhost:8081/releases</releases>
     <sonar>jdbc:oracle:thin:sonar/sonar@localhost/XE</sonar>
     <sonar.jdbc.username>sonar</sonar.jdbc.username>
     <format.conf> ${xyz_format}</format.conf>  <---- here is it!
    </properties>

Es klappt!

Iakov Senatov
quelle
0

Sie können mit so etwas gehen. Beachten Sie, dass Sie zwei Profile definieren müssen - eines, das für das Stammverzeichnis aktiviert wird, und eines für untergeordnete Profile. Dies setzt natürlich voraus, dass Kinder die gleiche Struktur haben, aber dies kann leicht angepasst werden.

    <profiles>
        <profile>
            <id>root-dir</id>
            <activation>
                <file>
                    <exists>${basedir}/lib</exists>
                </file>
            </activation>
            <properties>
                <project.libdir>${basedir}/lib</project.libdir>
            </properties>
        </profile>
        <profile>
            <id>child-dir</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <project.libdir>${basedir}/../../lib</project.libdir>
            </properties>
        </profile>
    </profiles>
kboom
quelle
0

Mit Maven 3.6.1 gibt $ {parent.basedir} aus einem untergeordneten Projekt das vollständig qualifizierte Verzeichnis des übergeordneten Projekts zurück.

Devdanke
quelle
Wie funktioniert es also, wenn ich den Vorfahren aller Projekte brauche, wenn einige untergeordnete Projekte möglicherweise eigene untergeordnete Projekte haben?
Christoffer Hammarström
0

Ich habe ein Stammverzeichnis für das übergeordnete POM mit $ {project.parent.basedir}.

Vlad Cheremisin
quelle