Praktik terbaik untuk menyalin file dengan Maven

193

Saya memiliki file konfigurasi dan berbagai dokumen yang ingin saya salin dari lingkungan dev ke direktori dev-server menggunakan Maven2. Anehnya, Maven tampaknya tidak kuat dalam tugas ini.

Beberapa opsi:

  • Sederhana menggunakan tugas salin di Maven
<copy file="src/main/resources/config.properties" tofile="${project.server.config}/config.properties"/>
  • Gunakan plugin Ant untuk menjalankan salinan dari Ant.

    • Bangun sebuah artefak dari zip tipe , di samping artefak "utama" dari POM yang biasanya dari jenis jar , kemudian buka kemasan artefak itu dari repositori ke direktori target.

    • plugin maven-resources , seperti yang disebutkan di bawah ini.

    • Plugin Maven Assembly - tetapi ini tampaknya memerlukan banyak definisi manual, ketika saya ingin melakukan sesuatu secara sederhana dan "konvensional."

    • Halaman ini bahkan menunjukkan cara membuat plugin untuk menyalin!

    • plugin unggah , seperti yang disebutkan di bawah ini.

    • maven-dependency-plugin dengan copy , seperti yang disebutkan di bawah ini.


Semua ini tampaknya tidak perlu ad hoc: Maven seharusnya unggul dalam melakukan tugas-tugas standar ini tanpa repot dan repot.

Ada saran?

Joshua Fox
sumber
2
Maven dibangun di sekitar gagasan siklus hidup dengan fase, menyalin file acak ke tugas server jauh tidak benar-benar cocok dengan ini. Selalu pikirkan proyek Anda secara keseluruhan.
André
3
"Semua ini tampaknya tidak perlu ad hoc: Maven seharusnya unggul dalam melakukan tugas-tugas standar ini tanpa repot dan repot." Apa yang Anda lakukan bukanlah tugas standar, per se. Jika artefak Anda adalah perang / telinga, maka ini akan sesederhana menggunakan plugin kargo (cargo.codehaus.org/Maven2+plugin#Maven2plugin-get…). Apa yang Anda gambarkan terdengar sangat spesifik untuk bagaimana Anda melakukan penyebaran dan bukan penyebaran wadah aplikasi java standar. Maven tidak benar-benar diarahkan untuk menangani aktivitas penyebaran waktu ke server langsung - ini diarahkan lebih untuk membangun / mengembangkan aktivitas.
whaley
67
@ André: Saya mendengar argumen itu berulang kali, tapi maaf, itu BS. Tidak ada yang salah dengan memikirkan proyek secara keseluruhan, tetapi bagian dari sistem pembangunan yang layak harus fungsionalitas yang memungkinkan saya mencapai tugas X dengan cara yang lurus ke depan, seperti menyalin file, dan Maven tidak bisa melakukan itu. Ada alasan mengapa begitu banyak proyek muncul akhir-akhir ini yang menganut paradigma build-scripts-are-code (seperti Gradle, SBT, atau Buildr).
Matthias
Saya akan merekomendasikan memiliki pom.xml untuk membangun artefak dan lainnya untuk menyebarkan artefak yang diberikan.
Thorbjørn Ravn Andersen
Semua saran di atas tampaknya masih tidak memungkinkan saya untuk menyalin file tertentu dari proyek / artefak yang berbeda ke proyek pakar. Saya memiliki beberapa file di bawah src / main / folder dalam sebuah artefak yang menjadi toples dan saya telah mencoba menggunakan dependensi-copy maven plugin namun saya belum menemukan cara untuk mengatakan file mana yang ingin saya salin dan saya mendapatkan seluruh jar. file dalam file rakitan sepanjang waktu. Semua saran lain di sini, seperti sumber daya, tampaknya tidak memungkinkan saya untuk menentukan artefak daripada sumber daya di dalam proyek
Alexandre Thenorio

Jawaban:

119

Jangan menghindar dari plugin Antrun. Hanya karena beberapa orang cenderung berpikir bahwa Ant dan Maven berselisih, mereka tidak. Gunakan tugas salin jika Anda perlu melakukan kustomisasi satu kali yang tidak dapat dihindari:

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

Dalam menjawab pertanyaan ini, saya fokus pada detail dari apa yang Anda minta. Bagaimana cara menyalin file? Pertanyaan dan nama variabel membawa saya ke pertanyaan yang lebih besar seperti: "Apakah ada cara yang lebih baik untuk berurusan dengan penyediaan server?" Gunakan Maven sebagai sistem pembangunan untuk menghasilkan artefak yang dapat digunakan, kemudian lakukan penyesuaian ini baik dalam modul terpisah atau di tempat lain sama sekali. Jika Anda berbagi sedikit lebih banyak dari lingkungan build Anda, mungkin ada cara yang lebih baik - ada plugin untuk menyediakan sejumlah server. Bisakah Anda memasang perakitan yang dibongkar di root server? Server apa yang Anda gunakan?

Sekali lagi, saya yakin ada cara yang lebih baik.

Tim O'Brien
sumber
Apakah deskriptor tugas sekarang tidak digunakan lagi?
Matt
3
@ Mat Ya, taskparameternya sudah tidak digunakan lagi ( Plugin Antrun ). Anda sebaiknya menggunakan target(sejak 1.5). Sayangnya ada beberapa contoh yang mencampuradukkan ini; misalnya targetparameter dan version<1,5.
cuh
Bagaimana ini bisa menjadi jawaban yang diterima? Tentunya harus ada permintaan perubahan ke pakar untuk membuat salinan hal sederhana.
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 jahat
sumber
Terima kasih @Peter, itu berguna. Saya sekarang menggunakan sumber daya-plugin tujuan copy-sumber bukannya antrun. Yang terakhir ini sebenarnya jauh lebih sederhana dan intuitif untuk didefinisikan, tetapi saya tidak bisa mendapatkannya (versi 1.3) untuk melewati semua properti kustom Maven (didefinisikan di bagian <properti>) untuk antrun, jadi saya beralih ke resource-plugin.
Cornel Masson
2
Dulu saya pikir ini adalah jawaban yang benar ... sampai saya menyadari bahwa plugin sumber daya tidak memiliki konfigurasi lewati. Antrun adalah cara untuk pergi.
Mike Post
Seharusnya tidak sulit untuk membuat profil lewati. Belum pernah menggunakan antrun, jadi saya tidak bisa mengatakan mana yang lebih mudah / lebih baik
Vivek Chavda
40

Untuk menyalin penggunaan file:

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

Untuk menyalin folder dengan sub-folder gunakan konfigurasi berikutnya:

           <configuration>
              <outputDirectory>${basedir}/target-folder</outputDirectory>
              <resources>          
                <resource>
                  <directory>/source-folder</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>  
Alexander Drobyshevsky
sumber
Pemfilteran dalam Maven mengacu pada interpolasi string, jadi saya hilangkan <filtering>untuk mencegah perubahan yang tidak diinginkan pada file skrip yang menggunakan ${...}variabel.
GeroldBroser mengembalikan Monica
20

Plugin dependensi pakar menyelamatkan saya dari banyak waktu dengan tugas semut:

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

The ketergantungan: copy adalah documentend, dan memiliki tujuan yang lebih berguna seperti membongkar.

Ban
sumber
3
Saya tidak menggunakan Ant selama bertahun-tahun, dan saya tidak ingin mulai melakukannya untuk hal yang begitu sederhana. Jadi terima kasih atas jawaban ini.
Gustave
17

Untuk tugas-tugas penyalinan yang sederhana, saya dapat merekomendasikan copy-rename-maven-plugin . Ini lurus ke depan dan mudah digunakan:

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

Jika Anda ingin menyalin lebih dari satu file, ganti <sourceFile>...</destinationFile>bagian itu dengan

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

Selain itu Anda dapat menentukan beberapa eksekusi dalam beberapa fase jika diperlukan, tujuan kedua adalah "ganti nama", yang hanya melakukan apa yang dikatakannya sementara sisa konfigurasi tetap sama. Untuk lebih banyak contoh penggunaan, rujuk ke Halaman Penggunaan .

Catatan : Plugin ini hanya dapat menyalin file, bukan direktori. (Terima kasih kepada @ james.garriss karena menemukan batasan ini.)

morten.c
sumber
2
Meskipun saya menyukai plugin ini, sangat mengejutkan bahwa ia tidak dapat menyalin direktori.
james.garriss
3
@ james.garriss Saya tidak mengetahui batasan ini, tetapi sayangnya Anda benar. Saya akan mengedit ini dalam jawaban saya untuk mungkin menghemat waktu beberapa orang menemukan ini sendiri.
morten.c
7

Solusi semut di atas paling mudah untuk dikonfigurasi, tetapi saya beruntung menggunakan plugin maven-upload-dari Atlassian. Saya tidak dapat menemukan dokumentasi yang bagus, berikut ini cara saya menggunakannya:

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

Variabel seperti "$ {jboss.host}" yang dirujuk di atas didefinisikan dalam ~ / .m2 / settings.xml saya dan diaktifkan menggunakan profil maven. Solusi ini tidak dibatasi untuk JBoss, ini hanya apa yang saya beri nama variabel saya. Saya memiliki profil untuk dev, test, dan live. Jadi untuk mengunggah telingaku ke contoh JBoss di lingkungan pengujian saya akan menjalankan:

mvn upload:upload -P test

Berikut ini cuplikan dari 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>
       ...

Catatan: Repo maven Atlassian yang memiliki plugin ini ada di sini: https://maven.atlassian.com/public/

Saya sarankan mengunduh sumber dan melihat dokumentasi di dalamnya untuk melihat semua fitur yang disediakan plugin.

`

Kyle Renfro
sumber
5

Nah, pakar seharusnya tidak baik dalam melakukan tugas-tugas granular yang baik, itu bukan bahasa scripting seperti bash atau semut, itu agak deklaratif - Anda mengatakan - saya perlu perang, atau telinga, dan Anda mendapatkannya. Namun jika Anda perlu menyesuaikan bagaimana perang atau telinga akan terlihat seperti di dalam, Anda punya masalah. Hanya saja tidak prosedural seperti semut, tetapi deklaratif. Ini memiliki beberapa pro di awal, dan bisa memiliki banyak kontra pada akhirnya.

Saya kira konsep awalnya adalah memiliki plugin yang bagus, "hanya berfungsi" tetapi kenyataannya berbeda jika Anda melakukan hal-hal yang tidak standar.

Namun, jika Anda cukup berupaya di pom Anda dan beberapa plugin khusus, Anda akan mendapatkan lingkungan build yang jauh lebih baik seperti semut misalnya (tergantung pada proyek Anda tentu saja, tetapi semakin dan semakin benar untuk proyek yang lebih besar).

siddhadev
sumber
4

Saya sudah memiliki pengalaman yang sangat baik dengan copy-maven-plugin . Ini memiliki sintaks yang jauh lebih mudah dan ringkas dibandingkan dengan maven-resources-plugin.

azerole
sumber
8
Sayangnya, copy-maven-plugin tidak kompatibel dengan maven 3.1.x
Hakan
2
Masalah pelacakan kompatibilitas dengan maven 3.1 ada di sana: github.com/evgeny-goldin/maven-plugins/issues/10
koppor
Lupakan plugin ini ... Cari garpu-nya
Kukeltje
4

Cara umum untuk menyalin file sewenang-wenang adalah dengan memanfaatkan abstraksi transportasi Maven Wagon . Ia bisa menangani berbagai tujuan melalui protokol seperti file, HTTP, FTP, SCPatauWebDAV .

Ada beberapa plugin yang menyediakan fasilitas untuk menyalin file melalui penggunaan Wagon. Yang paling menonjol adalah:

  • Keluar dari kotak Plugin Maven Deploy yang

    Ada deploy-filetujuannya. Itu cukup tidak fleksibel tetapi bisa menyelesaikan pekerjaan:

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

    Kerugian yang signifikan untuk digunakan Maven Deploy Pluginadalah bahwa ia dirancang untuk bekerja dengan repositori Maven. Ini mengasumsikan struktur dan metadata tertentu. Anda dapat melihat bahwa file tersebut ditempatkan di bawah foo/bar/1.0/file-1.0.extdan file checksum dibuat. Tidak ada jalan lain untuk ini.

  • Plugin Wagon Maven

    Gunakan upload-singletujuannya :

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

    Penggunaan Wagon Maven Pluginuntuk penyalinan sangat mudah dan tampaknya paling serbaguna.


Dalam contoh di atas <url>dapat berupa protokol yang didukung. Lihat daftar Penyedia Gerobak yang ada . Sebagai contoh

  • menyalin file secara lokal: file:///copy/to
  • menyalin file ke host jarak jauh yang menjalankan SSH:scp://host:22/copy/to


Contoh di atas melewatkan parameter plugin di baris perintah. Atau, plugin dapat dikonfigurasi secara langsung di POM. Maka doa akan sepertimvn deploy:deploy-file@configured-execution-id . Atau bisa juga terikat pada fase build tertentu.


Harap perhatikan bahwa untuk protokol yang suka SCPbekerja, Anda perlu menentukan ekstensi di POM:

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


Jika tujuan yang Anda salin membutuhkan otentikasi, kredensial dapat diberikan melalui Serverpengaturan . repositoryId/ serverIdditeruskan ke plugin harus cocok dengan server yang ditentukan dalam pengaturan.

ᄂ ᄀ
sumber
3

Saya hanya dapat berasumsi bahwa properti $ {project.server.config} Anda adalah sesuatu yang ditentukan khusus dan berada di luar tata letak direktori standar.

Jika demikian, maka saya akan menggunakan tugas salin.

ikan paus
sumber
Katakanlah saya berhati-hati untuk meletakkan file ke dalam tata letak direktori standar. Bisakah Maven menyalinnya ke target apa adanya, bukan di zip / toples?
Joshua Fox
2

Cara lain adalah untuk menggabungkan hal-hal ini menjadi sebuah artefak menggunakan plugin assembly. Kemudian Anda dapat menggunakan plugin dependensi untuk membongkar file-file ini di tempat yang Anda inginkan. Ada juga salin tujuan dalam plugin dependensi untuk menyalin artefak.

Brian Fox
sumber
1

Saya dapat mengumpulkan sejumlah sumber berbeda untuk jawaban ini:

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

Dari ~/.m2/settings.xml:

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

Kemudian jalankan perintah: (-X adalah untuk debug)

mvn -X upload:upload

Brett Dutton
sumber
-1

Untuk merangkum beberapa jawaban bagus di atas: Maven dirancang untuk membangun modul dan menyalin hasilnya ke repositori Maven. Setiap penyalinan modul ke direktori input penyebaran / pemasang harus dilakukan di luar konteks fungsi inti Maven, misalnya dengan perintah salin Ant / Maven .

Joshua Fox
sumber
Semut milik fungsionalitas inti Maven dan Wagon (meskipun plugin di sekitarnya bukan merupakan plugin inti Maven resmi).
GeroldBroser mengembalikan Monica