Mejores prácticas para copiar archivos con Maven

193

Tengo archivos de configuración y varios documentos que quiero copiar del entorno de desarrollo al directorio del servidor de desarrollo usando Maven2. Curiosamente, Maven no parece fuerte en esta tarea.

Algunas de las opciones:

  • Uso simple de una tarea de copia en Maven
<copy file="src/main/resources/config.properties" tofile="${project.server.config}/config.properties"/>
  • Use el complemento Ant para ejecutar la copia desde Ant.

    • Construya un artefacto de tipo zip , junto con el artefacto "principal" del POM que generalmente es de tipo jar , luego desempaquete ese artefacto del repositorio en el directorio de destino.

    • Complemento de recursos de Maven, como se menciona a continuación.

    • Complemento Maven Assembly, pero esto parece requerir muchas definiciones manuales, cuando quiero hacer las cosas de manera simple y "convencional".

    • ¡Esta página incluso muestra cómo crear un complemento para copiar!

    • Plugin de carga de Maven, como se menciona a continuación.

    • Maven-dependency-plugin con copia , como se menciona a continuación.


Todo esto parece innecesariamente ad hoc: se supone que Maven se destaca en hacer estas tareas estándar sin problemas ni molestias.

¿Algún consejo?

Joshua Fox
fuente
2
Maven se basa en la idea de un ciclo de vida con fases, la copia de archivos aleatorios a una tarea de servidor remoto realmente no encaja en esto. Siempre piense en su proyecto como un todo.
André
3
"Todo esto parece innecesariamente ad hoc: se supone que Maven se destaca en hacer estas tareas estándar sin problemas ni molestias". Lo que estás haciendo no es una tarea estándar, per se. Si su artefacto era una guerra / oído, entonces esto sería tan simple como usar el complemento de carga (cargo.codehaus.org/Maven2+plugin#Maven2plugin-get…). Lo que está describiendo suena muy específico a cómo está haciendo las implementaciones y no a las implementaciones estándar de contenedores de aplicaciones java. Maven no está realmente orientado a manejar actividades de tiempo de implementación en servidores activos, sino más bien a actividades de desarrollo / desarrollo.
whaley
67
@ André: escucho ese argumento una y otra vez, pero lo siento, eso es BS. No hay nada de malo en pensar en el proyecto en su conjunto, pero parte de cualquier sistema de compilación decente debe ser una funcionalidad que me permita realizar la tarea X de una manera directa, como copiar archivos, y Maven no puede hacer eso. Hay una razón por la que tantos proyectos surgieron últimamente que adoptan el paradigma de construir-scripts-son-código (como Gradle, SBT o Buildr).
Matthias
Recomendaría tener un pom.xml para construir los artefactos y otro para implementar un artefacto dado.
Thorbjørn Ravn Andersen
Todas las sugerencias anteriores todavía no parecen permitirme copiar un archivo específico de un proyecto / artefacto diferente en un proyecto maven. Tengo algunos archivos en la carpeta src / main / en un artefacto que se convierte en un jar y he intentado usar el complemento Maven de dependencia-copia, sin embargo, no he encontrado una manera de decir qué archivos quiero copiar y obtengo el jar completo archivo en el archivo de ensamblaje todo el tiempo. Todas las otras sugerencias aquí, como los recursos, no parecen permitirme especificar un artefacto en lugar de los recursos dentro del proyecto
Alexandre Thenorio

Respuestas:

119

No te alejes del complemento Antrun. Solo porque algunas personas tienden a pensar que Ant y Maven están en oposición, no lo están. Utilice la tarea de copia si necesita realizar alguna personalización única e inevitable:

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

Al responder a esta pregunta, me estoy centrando en los detalles de lo que preguntaste. ¿Cómo copio un archivo? La pregunta y el nombre de la variable me llevan a preguntas más grandes como: "¿Hay una mejor manera de lidiar con el aprovisionamiento del servidor?" Use Maven como un sistema de construcción para generar artefactos desplegables, luego realice estas personalizaciones en módulos separados o en otro lugar por completo. Si compartió un poco más de su entorno de compilación, podría haber una mejor manera: hay complementos para aprovisionar varios servidores. ¿Podría adjuntar un ensamblado desempaquetado en la raíz del servidor? ¿Qué servidor estás usando?

De nuevo, estoy seguro de que hay una mejor manera.

Tim O'Brien
fuente
¿El descriptor de tareas ahora está en desuso?
Matt
3
@ Matt Sí, el taskparámetro ahora está en desuso ( Plugin Antrun ). Debería usar targeten su lugar (desde 1.5). Desafortunadamente hay ejemplos que mezclan esto; por ejemplo, targetparámetro y version<1.5.
Cuh
¿Cómo puede ser esta la respuesta aceptada? Definitivamente debería haber una solicitud de cambio a Maven para hacer que la copia sea algo simple.
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 es malvado
fuente
Gracias @Peter, eso fue útil. Ahora uso el objetivo resources-plugin copy-resources en lugar de antrun. Este último es en realidad mucho más simple e intuitivo de definir, pero no pude lograr que (versión 1.3) pasara todas las propiedades personalizadas de Maven (definidas en la sección <properties>) a antrun, así que cambié a plugin de recursos.
Cornel Masson
2
Solía ​​pensar que esta era la respuesta correcta ... hasta que me di cuenta de que el complemento de recursos no tiene una configuración de omisión. Antrun es el camino a seguir.
Mike Post
No debería ser difícil crear un perfil de omisión. No he usado antrun, así que no puedo decir cuál es más fácil / mejor
Vivek Chavda
40

Para copiar un archivo use:

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

Para copiar una carpeta con subcarpetas, use la siguiente configuración:

           <configuration>
              <outputDirectory>${basedir}/target-folder</outputDirectory>
              <resources>          
                <resource>
                  <directory>/source-folder</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>  
Alexander Drobyshevsky
fuente
El filtrado en Maven se refiere a la interpolación de cadenas, por lo que omitiría <filtering>para evitar cambios no deseados, por ejemplo, en archivos de script que usan ${...}variables.
GeroldBroser reintegra a Mónica
20

El complemento de dependencia de Maven me ahorró mucho tiempo acariciando tareas de hormigas:

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

La dependencia: la copia es documental y tiene objetivos más útiles como desempaquetar.

Llantas
fuente
3
No usé Ant durante años, y no quiero comenzar a hacerlo por algo tan simple. Así que gracias por esta respuesta.
Gustave
17

Para tareas simples de copia, puedo recomendar copy-rename-maven-plugin . Es sencillo y fácil de usar:

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

Si desea copiar más de un archivo, reemplace la <sourceFile>...</destinationFile>parte con

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

Además, puede especificar ejecuciones múltiples en varias fases si es necesario, el segundo objetivo es "cambiar el nombre", que simplemente hace lo que dice mientras el resto de la configuración permanece igual. Para obtener más ejemplos de uso, consulte la página de uso .

Nota : Este complemento solo puede copiar archivos, no directorios. (Gracias a @ james.garriss por encontrar esta limitación).

morten.c
fuente
2
Aunque me gusta este complemento, es sorprendente que no pueda copiar directorios.
james.garriss
3
@ james.garriss No estaba al tanto de esta limitación, pero desafortunadamente tienes razón. Editaré esto en mi respuesta para quizás ahorrarle a algunas personas el tiempo de encontrar esto por sí mismos.
morten.c
7

La solución anterior es la más fácil de configurar, pero he tenido suerte con el complemento maven-upload-plugin de Atlassian. No pude encontrar buena documentación, así es como la uso:

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

Las variables como "$ {jboss.host}" mencionadas anteriormente están definidas en mi ~ / .m2 / settings.xml y se activan utilizando los perfiles de Maven. Esta solución no está limitada a JBoss, esto es justo lo que denominé mis variables. Tengo un perfil para dev, test y live. Entonces, para cargar mi oído a una instancia de jboss en un entorno de prueba, ejecutaría:

mvn upload:upload -P test

Aquí hay un fragmento de 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>
       ...

Notas: El repositorio de Maven de Atlassian que tiene este complemento está aquí: https://maven.atlassian.com/public/

Recomiendo descargar las fuentes y consultar la documentación para ver todas las características que proporciona el complemento.

``

Kyle Renfro
fuente
5

Bueno, se supone que maven no es bueno para hacer tareas granulares finas, no es un lenguaje de script como bash o ant, es más bien declarativo, dices, necesito una guerra o un oído, y lo entiendes. Sin embargo, si necesita personalizar el aspecto de la guerra o el oído en el interior, tiene un problema. Simplemente no es procesal como la hormiga, sino declarativo. Esto tiene algunas ventajas al principio y podría tener muchos inconvenientes al final.

Supongo que el concepto inicial era tener complementos finos, que "simplemente funcionan", pero la realidad es diferente si haces cosas no estándar.

Sin embargo, si pones suficiente esfuerzo en tus poms y pocos complementos personalizados, obtendrás un entorno de construcción mucho mejor como con Ant, por ejemplo (depende de tu proyecto, por supuesto, pero se vuelve cada vez más cierto para proyectos más grandes).

siddhadev
fuente
4

He tenido muy buena experiencia con copy-maven-plugin . Tiene una sintaxis mucho más conveniente y concisa en comparación con maven-resources-plugin.

azerole
fuente
8
Desafortunadamente, copy-maven-plugin no es compatible con maven 3.1.x
Hakan
2
El problema de seguimiento de la compatibilidad con maven 3.1 está ahí: github.com/evgeny-goldin/maven-plugins/issues/10
koppor
Olvídate de este complemento ... Busca sus tenedores
Kukeltje
4

Una forma genérica de copiar archivos arbitrarios es utilizar la abstracción de transporte de Maven Wagon . Puede manejar varios destinos a través de protocolos como file, HTTP, FTP, SCPoWebDAV .

Hay algunos complementos que proporcionan facilidades para copiar archivos mediante el uso de Wagon. Los más notables son:

  • Fuera de la caja Maven Implementar Plugin

    Ahí está el deploy-fileobjetivo. Es bastante inflexible pero puede hacer el trabajo:

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

    Una desventaja significativa de usar Maven Deploy Plugines que está diseñado para trabajar con repositorios Maven. Asume una estructura y metadatos particulares. Puede ver que el archivo se coloca debajo foo/bar/1.0/file-1.0.exty se crean archivos de suma de comprobación. No hay forma de evitar esto.

  • Complemento Wagon Maven

    Usa el upload-singleobjetivo :

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

    El uso de Wagon Maven Pluginpara copiar es sencillo y parece ser el más versátil.


En los ejemplos anteriores <url>puede ser de cualquier protocolo compatible. Consulte la lista de proveedores de vagones existentes . Por ejemplo

  • copiando el archivo localmente: file:///copy/to
  • copiando el archivo al host remoto que se ejecuta SSH:scp://host:22/copy/to


Los ejemplos anteriores pasan los parámetros del complemento en la línea de comando. Alternativamente, los complementos se pueden configurar directamente en POM. Entonces la invocación será simplemente comomvn deploy:deploy-file@configured-execution-id . O puede estar vinculado a una fase de construcción particular.


Tenga en cuenta que para protocolos SCPque funcionen deberá definir una extensión en su POM:

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


Si el destino al que está copiando requiere autenticación, se pueden proporcionar credenciales a través de la Serverconfiguración . repositoryId/ serverIdpasado a los complementos debe coincidir con el servidor definido en la configuración.

ᄂ ᄀ
fuente
3

Solo puedo suponer que su propiedad $ {project.server.config} es algo personalizado y está fuera del diseño estándar del directorio.

Si es así, usaría la tarea de copia.

Whaley
fuente
Digamos que me encargo de colocar los archivos en el diseño de directorio estándar. ¿Puede Maven copiarlos en el destino tal cual, no en un zip / jar?
Joshua Fox
2

Otra forma es agrupar estas cosas en un artefacto utilizando el complemento de ensamblaje. Luego puede usar el complemento de dependencia para descomprimir estos archivos donde desee. También hay objetivos de copia en el complemento de dependencia para copiar artefactos.

Brian Fox
fuente
1

Pude reunir varias fuentes diferentes para esta respuesta:

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

De ~/.m2/settings.xml:

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

Luego ejecute el comando: (-X es para depurar)

mvn -X upload:upload

Brett Dutton
fuente
-1

Para resumir algunas de las buenas respuestas anteriores: Maven está diseñado para construir módulos y copiar los resultados a un repositorio de Maven. Cualquier copia de módulos a un directorio de implementación / entrada de instalador debe realizarse fuera del contexto de la funcionalidad principal de Maven, por ejemplo, con el comando de copia Ant / Maven .

Joshua Fox
fuente
Ant pertenece a la funcionalidad principal de Maven y Wagon también (aunque el complemento que lo rodea no es un complemento oficial de Maven).
GeroldBroser reintegra a Mónica el