Best Practices zum Kopieren von Dateien mit Maven

193

Ich habe Konfigurationsdateien und verschiedene Dokumente, die ich mit Maven2 aus der Dev-Umgebung in das Dev-Server-Verzeichnis kopieren möchte. Seltsamerweise scheint Maven bei dieser Aufgabe nicht stark zu sein.

Einige der Optionen:

  • Verwenden Sie einfach eine Kopieraufgabe in Maven
<copy file="src/main/resources/config.properties" tofile="${project.server.config}/config.properties"/>
  • Verwenden Sie das Ant-Plugin, um eine Kopie von Ant auszuführen .

    • Erstellen Sie ein Artefakt vom Typ zip neben dem "Haupt" -Artefakt des POM, das normalerweise vom Typ jar ist , und entpacken Sie dieses Artefakt aus dem Repository in das Zielverzeichnis.

    • Maven-Resources- Plugin, wie unten erwähnt.

    • Maven Assembly Plugin - aber dies scheint viele manuelle Definitionen zu erfordern, wenn ich Dinge einfach und "konventionell" machen möchte.

    • Diese Seite zeigt sogar, wie man ein Plugin zum Kopieren erstellt!

    • Maven-Upload- Plugin, wie unten erwähnt.

    • Maven-Dependency-Plugin mit Kopie , wie unten erwähnt.


All dies scheint unnötig ad hoc zu sein: Maven soll diese Standardaufgaben ohne viel Aufhebens und Mühe erledigen.

Irgendein Rat?

Joshua Fox
quelle
2
Maven basiert auf der Idee eines Lebenszyklus mit Phasen. Das Kopieren von zufälligen Dateien auf eine Remote-Server-Aufgabe passt nicht wirklich dazu. Denken Sie immer an Ihr Projekt als Ganzes.
André
3
„All dies scheint unnötig ad hoc zu sein: Maven soll diese Standardaufgaben ohne viel Aufhebens und Mühe erledigen.“ Was Sie tun, ist per se keine Standardaufgabe. Wenn Ihr Artefakt ein Krieg / Ohr wäre, wäre dies so einfach wie die Verwendung des Fracht-Plugins (load.codehaus.org/Maven2+plugin#Maven2plugin-get…). Was Sie beschreiben, klingt sehr spezifisch für die Art und Weise, wie Sie Bereitstellungen durchführen, und nicht für Standardbereitstellungen von Java-Anwendungscontainern. Maven ist nicht wirklich darauf ausgerichtet, Aktivitäten zur Bereitstellungszeit auf Live-Servern zu verarbeiten - es ist eher darauf ausgerichtet, Aktivitäten zu erstellen / zu entwickeln.
Whaley
67
@ André: Ich höre dieses Argument immer und immer wieder, aber sorry, das ist BS. Es ist nichts Falsches daran, das Projekt als Ganzes zu betrachten, aber ein Teil eines anständigen Build-Systems sollte eine Funktionalität sein, mit der ich Aufgabe X auf einfache Weise ausführen kann, z. B. das Kopieren von Dateien, und Maven kann das nicht. Es gibt einen Grund, warum in letzter Zeit so viele Projekte aufgetaucht sind, die das Paradigma von Build-Skripten und Code umfassen (wie Gradle, SBT oder Buildr).
Matthias
Ich würde empfehlen , für eine pom.xml mit Bau der Artefakte und eine andere für die Bereitstellung eines bestimmten Artefakt.
Thorbjørn Ravn Andersen
Alle obigen Vorschläge scheinen mir immer noch nicht zu erlauben, eine bestimmte Datei aus einem anderen Projekt / Artefakt in ein Maven-Projekt zu kopieren. Ich habe einige Dateien unter src / main / folder in einem Artefakt, das zu einem JAR wird, und ich habe versucht, das Maven-Plugin für Abhängigkeitskopien zu verwenden. Ich habe jedoch keine Möglichkeit gefunden, zu sagen, welche Dateien ich kopieren möchte, und ich erhalte das gesamte JAR Datei in der Assembly-Datei die ganze Zeit. Alle anderen Vorschläge hier, wie Ressourcen, scheinen es mir nicht zu erlauben, ein Artefakt anstelle der Ressourcen innerhalb des Projekts anzugeben
Alexandre Thenorio

Antworten:

119

Scheuen Sie sich nicht vor dem Antrun-Plugin. Nur weil manche Leute glauben, Ant und Maven seien in Opposition, sind sie es nicht. Verwenden Sie die Kopieraufgabe, wenn Sie eine unvermeidbare einmalige Anpassung vornehmen müssen:

<project>
  [...]
  <build>
    <plugins>
      [...]
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <phase>deploy</phase>
            <configuration>
              <tasks>

                <!--
                  Place any Ant task here. You can add anything
                  you can add between <target> and </target> in a
                  build.xml.
                -->

              </tasks>
            </configuration>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

Bei der Beantwortung dieser Frage konzentriere ich mich auf die Details Ihrer Fragen. Wie kopiere ich eine Datei? Die Frage und der Variablenname führen mich zu größeren Fragen wie: "Gibt es einen besseren Weg, um mit der Serverbereitstellung umzugehen?" Verwenden Sie Maven als Build-System, um bereitstellbare Artefakte zu generieren, und führen Sie diese Anpassungen dann entweder in separaten Modulen oder an einem anderen Ort vollständig durch. Wenn Sie ein bisschen mehr von Ihrer Build-Umgebung freigegeben haben, gibt es möglicherweise einen besseren Weg - es gibt Plugins, um eine Reihe von Servern bereitzustellen. Könnten Sie eine Assembly anhängen, die im Stammverzeichnis des Servers entpackt ist? Welchen Server verwenden Sie?

Ich bin mir wieder sicher, dass es einen besseren Weg gibt.

Tim O'Brien
quelle
Ist der Aufgabendeskriptor jetzt veraltet?
Matt
3
@Matt Ja, der taskParameter ist jetzt veraltet ( Antrun Plugin ). Sie sollten targetstattdessen verwenden (seit 1.5). Leider gibt es Beispiele, die dies verwechseln; zB targetParameter und version<1.5.
Cuh
Wie kann dies die akzeptierte Antwort sein? Auf jeden Fall sollte es eine Änderungsanforderung an maven geben, um das Kopieren zu einer einfachen Sache zu machen.
Wolfgang Fahl
137
<build>
    <plugins>
        ...
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.3</version>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include> **/*.properties</include>
            </includes>
        </resource>
    </resources>
    ...
</build>
kay - SE ist böse
quelle
Danke @Peter, das war nützlich. Ich verwende jetzt das Ziel Ressourcen-Plugin Kopieren-Ressourcen anstelle von Antrun. Letzteres ist eigentlich viel einfacher und intuitiver zu definieren, aber ich konnte es nicht schaffen (Version 1.3), alle benutzerdefinierten Maven-Eigenschaften (definiert im Abschnitt <Eigenschaften>) an antrun zu übergeben, also habe ich zum Ressourcen-Plugin gewechselt.
Cornel Masson
2
Früher dachte ich, dies sei die richtige Antwort ... bis mir klar wurde, dass das Ressourcen-Plugin keine Sprungkonfiguration hat. Antrun ist der richtige Weg.
Mike Post
Es sollte nicht schwierig sein, ein Sprungprofil zu erstellen. Ich habe kein Antrun verwendet, daher kann ich nicht sagen, was einfacher / besser ist
Vivek Chavda,
40

Um eine Datei zu kopieren, verwenden Sie:

        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>copy-resource-one</id>
                    <phase>install</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>

                    <configuration>
                        <outputDirectory>${basedir}/destination-folder</outputDirectory>
                        <resources>
                            <resource>
                                <directory>/source-folder</directory>
                                <includes>
                                    <include>file.jar</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
           </executions>
        </plugin>

Verwenden Sie die nächste Konfiguration, um Ordner mit Unterordnern zu kopieren:

           <configuration>
              <outputDirectory>${basedir}/target-folder</outputDirectory>
              <resources>          
                <resource>
                  <directory>/source-folder</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>  
Alexander Drobyshevsky
quelle
Das Filtern in Maven bezieht sich auf die Zeichenfolgeninterpolation, daher würde ich es unterlassen <filtering>, unerwünschte Änderungen an z. B. Skriptdateien zu verhindern, die ${...}Variablen verwenden.
GeroldBroser setzt Monica
20

Das Maven-Abhängigkeits-Plugin hat mir viel Zeit beim Stöbern mit Ameisenaufgaben gespart:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>install-jar</id>
            <phase>install</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>...</groupId>
                        <artifactId>...</artifactId>
                        <version>...</version>
                    </artifactItem>
                </artifactItems>
                <outputDirectory>...</outputDirectory>
                <stripVersion>true</stripVersion>
            </configuration>
        </execution>
    </executions>
</plugin>

Die Abhängigkeit: copy ist documentend und hat nützlichere Ziele wie das Entpacken.

Reifen
quelle
3
Ich habe Ant jahrelang nicht benutzt und ich möchte nicht damit anfangen, es für eine so einfache Sache zu tun. Also danke für diese Antwort.
Gustave
17

Für einfache Kopieraufgaben kann ich das Copy-Rename-Maven-Plugin empfehlen . Es ist unkompliziert und einfach zu bedienen:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>com.coderplus.maven.plugins</groupId>
        <artifactId>copy-rename-maven-plugin</artifactId>
        <version>1.0</version>
        <executions>
          <execution>
            <id>copy-file</id>
            <phase>generate-sources</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <sourceFile>src/someDirectory/test.environment.properties</sourceFile>
              <destinationFile>target/someDir/environment.properties</destinationFile>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Wenn Sie mehr als eine Datei kopieren möchten, ersetzen Sie das <sourceFile>...</destinationFile>Teil durch

<fileSets>
  <fileSet>
    <sourceFile>src/someDirectory/test.environment.properties</sourceFile>
    <destinationFile>target/someDir/environment.properties</destinationFile>
  </fileSet>
  <fileSet>
    <sourceFile>src/someDirectory/test.logback.xml</sourceFile>
    <destinationFile>target/someDir/logback.xml</destinationFile>
  </fileSet>                
</fileSets>

Darüber hinaus können Sie bei Bedarf mehrere Ausführungen in mehreren Phasen angeben. Das zweite Ziel ist "Umbenennen", das einfach das tut, was es sagt, während der Rest der Konfiguration gleich bleibt. Weitere Anwendungsbeispiele finden Sie auf der Nutzungsseite .

Hinweis : Dieses Plugin kann nur Dateien kopieren, keine Verzeichnisse. (Vielen Dank an @ james.garriss für das Auffinden dieser Einschränkung.)

morten.c
quelle
2
Obwohl ich dieses Plugin mag, ist es erstaunlich, dass es keine Verzeichnisse kopieren kann.
James.garriss
3
@ james.garriss Ich war mir dieser Einschränkung nicht bewusst, aber leider hast du recht. Ich werde dies in meiner Antwort bearbeiten, um einigen Leuten vielleicht die Zeit zu ersparen, dies selbst zu finden.
morten.c
7

Die oben genannte Ant-Lösung ist am einfachsten zu konfigurieren, aber ich hatte Glück mit dem Maven-Upload-Plugin von Atlassian. Ich konnte keine gute Dokumentation finden. So verwende ich sie:

<build>
  <plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-upload-plugin</artifactId>
    <version>1.1</version>
    <configuration>
       <resourceSrc>
             ${project.build.directory}/${project.build.finalName}.${project.packaging}
       </resourceSrc>
       <resourceDest>${jboss.deployDir}</resourceDest>
       <serverId>${jboss.host}</serverId>
       <url>${jboss.deployUrl}</url>
     </configuration>
  </plugin>
</build>

Die Variablen wie "$ {jboss.host}", auf die oben verwiesen wird, sind in meiner Datei ~ / .m2 / settings.xml definiert und werden mithilfe von Maven-Profilen aktiviert. Diese Lösung ist nicht auf JBoss beschränkt, sondern genau das, was ich meine Variablen genannt habe. Ich habe ein Profil für Entwickler, Test und Live. Um mein Ohr auf eine jboss-Instanz in einer Testumgebung hochzuladen, würde ich Folgendes ausführen:

mvn upload:upload -P test

Hier ist ein Ausschnitt aus settings.xml:

<server>
  <id>localhost</id>
  <username>username</username>
  <password>{Pz+6YRsDJ8dUJD7XE8=} an encrypted password. Supported since maven 2.1</password>
</server>
...
<profiles>
  <profile>
    <id>dev</id>
    <properties>
      <jboss.host>localhost</jboss.host> 
      <jboss.deployDir>/opt/jboss/server/default/deploy/</jboss.deployDir>
      <jboss.deployUrl>scp://root@localhost</jboss.deployUrl>
    </properties>
  </profile>
  <profile>
    <id>test</id>
    <properties>
       <jboss.host>testserver</jboss.host>
       ...

Anmerkungen: Das Atlassian Maven Repo mit diesem Plugin finden Sie hier: https://maven.atlassian.com/public/

Ich empfehle, die Quellen herunterzuladen und in der Dokumentation nachzuschauen, um alle Funktionen des Plugins zu sehen.

`

Kyle Renfro
quelle
5

Nun, Maven soll nicht gut darin sein, feine granulare Aufgaben zu erledigen, es ist keine Skriptsprache wie Bash oder Ant, es ist eher deklarativ - Sie sagen - ich brauche einen Krieg oder ein Ohr, und Sie verstehen es. Wenn Sie jedoch anpassen müssen, wie der Krieg oder das Ohr im Inneren aussehen sollen, haben Sie ein Problem. Es ist einfach nicht prozedural wie Ameise, sondern deklarativ. Dies hat am Anfang einige Vorteile und könnte am Ende viele Nachteile haben.

Ich denke, das ursprüngliche Konzept bestand darin, feine Plugins zu haben, die "einfach funktionieren", aber die Realität sieht anders aus, wenn Sie nicht standardmäßige Dinge tun.

Wenn Sie jedoch genügend Aufwand in Ihre Poms und einige benutzerdefinierte Plugins investieren, erhalten Sie eine viel bessere Build-Umgebung als beispielsweise bei ant (hängt natürlich von Ihrem Projekt ab, wird jedoch bei größeren Projekten immer wahrer).

Siddhadev
quelle
4

Ich habe sehr gute Erfahrungen mit Copy-Maven-Plugin gemacht . Es hat eine viel bequemere und präzisere Syntax im Vergleich zum Maven-Resources-Plugin.

Azerole
quelle
8
Leider ist Copy-Maven-Plugin nicht kompatibel mit Maven 3.1.x
Hakan
2
Das Problem, das die Kompatibilität mit Maven 3.1 verfolgt, ist da: github.com/evgeny-goldin/maven-plugins/issues/10
koppor
Vergessen Sie dieses Plugin ... Suchen Sie nach seinen Gabeln
Kukeltje
4

Eine generische Methode zum Kopieren beliebiger Dateien ist die Verwendung der Maven Wagon- Transportabstraktion. Es kann verschiedene Ziele behandeln über Protokolle wie file, HTTP, FTP, SCPoder WebDAV.

Es gibt einige Plugins, die Funktionen zum Kopieren von Dateien mithilfe von verwenden Wagon. Am bemerkenswertesten sind:

  • Out-of-the-Box Maven Deploy Plugin

    Da ist das deploy-fileZiel. Es ist ziemlich unflexibel, kann aber die Arbeit erledigen:

    mvn deploy:deploy-file -Dfile=/path/to/your/file.ext -DgroupId=foo 
    -DartifactId=bar -Dversion=1.0 -Durl=<url> -DgeneratePom=false

    Ein wesentlicher Nachteil der Verwendung Maven Deploy Pluginbesteht darin, dass sie für die Arbeit mit Maven-Repositorys vorgesehen ist. Es nimmt eine bestimmte Struktur und Metadaten an. Sie können sehen, dass die Datei unter platziert wird foo/bar/1.0/file-1.0.extund Prüfsummendateien erstellt werden. Daran führt kein Weg vorbei.

  • Wagon Maven Plugin

    Verwenden Sie das upload-singleZiel :

    mvn org.codehaus.mojo:wagon-maven-plugin:upload-single
    -Dwagon.fromFile=/path/to/your/file.ext -Dwagon.url=<url>

    Die Verwendung Wagon Maven Pluginzum Kopieren ist unkompliziert und scheint die vielseitigste zu sein.


In den obigen Beispielen <url>kann jedes Protokoll unterstützt werden. Siehe die Liste der vorhandenen Wagenanbieter . Beispielsweise

  • Datei lokal kopieren: file:///copy/to
  • Kopieren der Datei auf einen Remote-Host, der ausgeführt wird SSH:scp://host:22/copy/to


Die obigen Beispiele übergeben Plugin-Parameter in der Befehlszeile. Alternativ können Plugins direkt in konfiguriert werden POM. Dann wird der Aufruf einfach so sein mvn deploy:deploy-file@configured-execution-id. Oder es kann an eine bestimmte Erstellungsphase gebunden sein.


Bitte beachten Sie, dass Sie für Protokolle, die gerne SCPfunktionieren, eine Erweiterung in Ihrem Verzeichnis definieren müssen POM:

<build>
  [...]
  <extensions>
    <extension>
      <groupId>org.apache.maven.wagon</groupId>
      <artifactId>wagon-ssh</artifactId>
      <version>2.12</version>
    </extension>
  </extensions>


Wenn für das zu kopierende Ziel eine Authentifizierung erforderlich ist, können Anmeldeinformationen über die ServerEinstellungen bereitgestellt werden . repositoryId/ serverIdan die Plugins übergeben muss mit dem in den Einstellungen definierten Server übereinstimmen.

ᄂ ᄀ
quelle
3

Ich kann nur davon ausgehen, dass Ihre Eigenschaft $ {project.server.config} benutzerdefiniert ist und außerhalb des Standardverzeichnislayouts liegt.

Wenn ja, dann würde ich die Kopieraufgabe verwenden.

Whaley
quelle
Angenommen, ich achte darauf, die Dateien in das Standardverzeichnislayout zu verschieben. Kann Maven sie so wie sie sind auf das Ziel kopieren, nicht in einem Reißverschluss / Glas?
Joshua Fox
2

Eine andere Möglichkeit besteht darin, diese Dinge mithilfe des Assembly-Plugins zu einem Artefakt zu bündeln. Anschließend können Sie das Abhängigkeits-Plugin verwenden, um diese Dateien an der gewünschten Stelle zu entpacken. Es gibt auch Kopierziele im Abhängigkeits-Plugin, um Artefakte zu kopieren.

Brian Fox
quelle
1

Für diese Antwort konnte ich verschiedene Quellen zusammenstellen:

...
<repository>
    <id>atlassian</id>
    <name>Atlassian Repo</name>
    <url>https://maven.atlassian.com/content/repositories/atlassian-public</url>
</repository>
...
<dependency>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-upload-plugin</artifactId>
    <version>1.1</version>
</dependency>
...
<plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-upload-plugin</artifactId>
    <version>1.1</version>
    <configuration>
        <serverId>jira-repo</serverId>
        <resourceSrc>
            ${project.build.directory}/${project.build.finalName}.${project.packaging}
        </resourceSrc>
        <resourceDest>opt/jira/webapps</resourceDest> <!-- note: no leading slash -->
        <url>scp://root@jira</url>
    </configuration>
</plugin>
...

Von ~/.m2/settings.xml:

...
<servers>
  <server>
    <id>jira-repo</id>
    <username>myusername</username>
    <password>mypassword</password>
  </server>
</servers>
...

Führen Sie dann den folgenden Befehl aus: (-X dient zum Debuggen)

mvn -X upload:upload

Brett Dutton
quelle
-1

Um einige der oben genannten guten Antworten zusammenzufassen: Maven wurde entwickelt, um Module zu erstellen und die Ergebnisse in ein Maven-Repository zu kopieren. Das Kopieren von Modulen in ein Deployment- / Installer-Input-Verzeichnis muss außerhalb des Kontexts der Kernfunktionalität von Maven erfolgen, z. B. mit dem Befehl Ant / Maven copy .

Joshua Fox
quelle
Ant gehört zu Mavens Kernfunktionalität, ebenso wie Wagon (obwohl das Plugin kein offizielles Maven-Kern-Plugin ist).
GeroldBroser setzt Monica