Práticas recomendadas para copiar arquivos com o Maven

193

Tenho arquivos de configuração e vários documentos que desejo copiar do ambiente de desenvolvimento para o diretório dev-server usando o Maven2. Estranhamente, Maven não parece forte nessa tarefa.

Algumas das opções:

  • Simples usar uma tarefa de cópia no Maven
<copy file="src/main/resources/config.properties" tofile="${project.server.config}/config.properties"/>
  • Use o plugin Ant para executar uma cópia do Ant.

    • Construa um artefato do tipo zip , juntamente com o artefato "principal" do POM, que geralmente é do tipo jar , e descompacte esse artefato do repositório no diretório de destino.

    • plug - in maven-resources , conforme mencionado abaixo.

    • Maven Assembly plugin - mas isso parece exigir muitas definições manuais, quando eu quero fazer as coisas de maneira simples e "convencional".

    • Esta página mostra até como criar um plugin para copiar!

    • maven-upload plugin, como mencionado abaixo.

    • maven-dependency-plugin com cópia , conforme mencionado abaixo.


Tudo isso parece desnecessariamente ad hoc: supõe-se que o Maven seja excelente ao executar essas tarefas padrão sem problemas.

Algum conselho?

Joshua Fox
fonte
2
O Maven é construído com base na idéia de um ciclo de vida com fases, a cópia aleatória de arquivos em uma tarefa de servidor remoto não se encaixa realmente nisso. Sempre pense no seu projeto como um todo.
André
3
"Tudo isso parece desnecessariamente ad hoc: o Maven deve se sobressair ao executar essas tarefas padrão sem problemas." O que você está fazendo não é uma tarefa padrão, por si só. Se seu artefato fosse uma guerra / orelha, seria tão simples quanto usar o plug-in de carga (cargo.codehaus.org/Maven2+plugin#Maven2plugin-get…). O que você está descrevendo parece altamente específico de como você está fazendo implantações e não implantações padrão de contêiner de aplicativos java. O Maven não é realmente voltado para lidar com atividades de tempo de implantação em servidores ativos - é voltado mais para atividades de criação / desenvolvimento.
Whaley 9/09/09
67
@ André: eu ouço esse argumento repetidamente, mas desculpe, isso é BS. Não há nada de errado em pensar no projeto como um todo, mas parte de qualquer sistema de construção decente deve ser uma funcionalidade que me permita realizar a tarefa X de maneira direta, como copiar arquivos, e o Maven não pode fazer isso. Há uma razão pela qual tantos projetos surgiram ultimamente que adotam o paradigma build-scripts-are-code (como Gradle, SBT ou Buildr).
Matthias
Eu recomendaria ter um pom.xml para construir os artefatos e outro para implantar um determinado artefato.
Thorbjørn Ravn Andersen
Todas as sugestões acima ainda parecem não me permitir copiar um arquivo específico de um projeto / artefato diferente em um projeto de preparação. Tenho alguns arquivos na pasta src / main / em um artefato que se torna um jar e tentei usar o plugin maven de cópia de dependência, mas não encontrei uma maneira de dizer quais arquivos quero copiar e recebo o jar inteiro arquivo no arquivo de montagem o tempo todo. Todas as outras sugestões aqui, como recursos, parecem não me permitir especificar um artefato, e não os recursos dentro do projeto
Alexandre Thenorio

Respostas:

119

Não coíbe o plug-in Antrun. Só porque algumas pessoas tendem a pensar que Ant e Maven estão em oposição, eles não estão. Use a tarefa de cópia se precisar executar uma personalização única e inevitável:

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

Ao responder a essa pergunta, estou focando nos detalhes do que você perguntou. Como copio um arquivo? A pergunta e o nome da variável me levam a perguntas maiores, como: "Existe uma maneira melhor de lidar com o provisionamento de servidores?" Use o Maven como um sistema de construção para gerar artefato implementável e, em seguida, execute essas personalizações em módulos separados ou em outro local totalmente. Se você compartilhou um pouco mais do seu ambiente de construção, pode haver uma maneira melhor - existem plugins para provisionar vários servidores. Você poderia anexar um assembly descompactado na raiz do servidor? Qual servidor você está usando?

Mais uma vez, tenho certeza de que há uma maneira melhor.

Tim O'Brien
fonte
O descritor de tarefas agora está obsoleto?
19411 Matt
3
@ Matt Sim, o taskparâmetro agora está obsoleto ( Antrun Plugin ). Você deve usar target(em vez de 1.5). Infelizmente, existem exemplos que misturam isso; por exemplo, targetparâmetro e version<1,5.
cuh
Como essa pode ser a resposta aceita? Definitivamente, deve haver uma solicitação de alteração a ser feita para tornar a cópia uma coisa simples.
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 é mau
fonte
Obrigado @ Peter, isso foi útil. Agora uso o objetivo de cópia de recursos do plug-in de recursos, em vez de antrun. O último é realmente muito mais simples e intuitivo de definir, mas não consegui (na versão 1.3) passar todas as propriedades personalizadas do Maven (definidas na seção <properties>) para o antrun, então mudei para o plugin de recursos.
Cornel Masson
2
Eu achava que essa era a resposta correta ... até que percebi que o plug-in de recursos não tem uma configuração de ignorar. Antrun é o caminho a percorrer.
Mike Post
Não deve ser difícil criar um perfil de salto. Não usei antrun, então eu não posso dizer que é mais fácil / melhor
Vivek Chavda
40

Para copiar um arquivo, 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 uma pasta com subpastas, use a próxima configuração:

           <configuration>
              <outputDirectory>${basedir}/target-folder</outputDirectory>
              <resources>          
                <resource>
                  <directory>/source-folder</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>  
Alexander Drobyshevsky
fonte
A filtragem no Maven se refere à interpolação de strings, portanto, eu omitiria <filtering>para impedir alterações indesejadas em, por exemplo, arquivos de script que usam ${...}variáveis.
GeroldBroser restabelece Monica 04/02
20

O plug-in de dependência maven me salvou muito tempo brincando com tarefas ant:

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

A dependência: copy é documentada e possui objetivos mais úteis, como descompactar.

Pneus
fonte
3
Não uso o Ant há anos e não quero começar a fazê-lo por uma coisa tão simples. Então, obrigado por esta resposta.
Gustave
17

Para tarefas simples de cópia, recomendo copiar-renomear-maven-plugin . É direto e simples 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>

Se você deseja copiar mais de um arquivo, substitua a <sourceFile>...</destinationFile>peça por

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

Além disso, você pode especificar várias execuções em várias fases, se necessário, o segundo objetivo é "renomear", que simplesmente faz o que diz enquanto o restante da configuração permanece o mesmo. Para mais exemplos de uso, consulte a Página de uso .

Nota : Este plugin pode copiar apenas arquivos, não diretórios. (Obrigado a @ james.garriss por encontrar essa limitação.)

morten.c
fonte
2
Embora eu goste deste plugin, é surpreendente que ele não possa copiar diretórios.
James.garriss
3
@ james.garriss Eu não estava ciente dessa limitação, mas infelizmente você está certo. Vou editar isso na minha resposta para talvez poupar algumas pessoas o tempo de encontrar isso por si mesmas.
morten.c
7

A solução ant acima é mais fácil de configurar, mas tive sorte usando o maven-upload-plugin do Atlassian. Não consegui encontrar boa documentação, eis como a 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>

As variáveis ​​como "$ {jboss.host}" referenciadas acima são definidas em meu ~ / .m2 / settings.xml e são ativadas usando perfis maven. Esta solução não é restrita ao JBoss, é exatamente isso que chamei de minhas variáveis. Eu tenho um perfil para dev, test e live. Então, para carregar meu ouvido em uma instância do jboss no ambiente de teste, eu executaria:

mvn upload:upload -P test

Aqui está um snipet 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: O repositório de máquinas Atlassian que contém este plugin está aqui: https://maven.atlassian.com/public/

Eu recomendo baixar as fontes e ver a documentação dentro para ver todos os recursos que o plug-in fornece.

`

Kyle Renfro
fonte
5

Bem, o maven não deve ser bom em executar tarefas granulares finas, não é uma linguagem de script como bash ou ant, é bastante declarativa - você diz - eu preciso de uma guerra ou de um ouvido, e você entende. No entanto, se você precisar personalizar a aparência da guerra ou do ouvido por dentro, você terá um problema. Não é apenas processual como formiga, mas declarativo. Isso tem alguns profissionais no começo e pode ter muitos contras no final.

Eu acho que o conceito inicial era ter plugins finos, que "funcionam", mas a realidade é diferente se você fizer coisas fora do padrão.

Se você, no entanto, se esforçar o suficiente em seus poms e em alguns plugins personalizados, obterá um ambiente de construção muito melhor como no ant, por exemplo (depende do seu projeto, é claro, mas isso se torna cada vez mais verdadeiro para projetos maiores).

siddhadev
fonte
4

Eu tive uma experiência muito boa com o copy-maven-plugin . Possui uma sintaxe muito mais conveniente e concisa em comparação com o maven-resources-plugin.

azerole
fonte
8
Infelizmente, o copy-maven-plugin não é compatível com o maven 3.1.x
Hakan
2
O problema que rastreia a compatibilidade com o maven 3.1 está lá: github.com/evgeny-goldin/maven-plugins/issues/10
koppor
Esqueça este plugin ... Olhe para os seus garfos
Kukeltje
4

Uma maneira genérica de copiar arquivos arbitrários é utilizar a abstração de transporte do Maven Wagon . Ele pode lidar com vários destinos através de protocolos como file, HTTP, FTP, SCPouWebDAV .

Existem alguns plugins que fornecem recursos para copiar arquivos através do uso de Wagon. Os mais notáveis ​​são:

  • Sai da caixa Maven Deploy Plugin

    Existe o deploy-fileobjetivo. É bastante inflexível, mas pode fazer o trabalho:

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

    A desvantagem significativa do uso Maven Deploy Pluginé que ele foi designado para trabalhar com repositórios Maven. Ele assume estrutura e metadados específicos. Você pode ver que o arquivo é colocado em baixo foo/bar/1.0/file-1.0.exte os arquivos de soma de verificação são criados. Não há como contornar isso.

  • Wagon Maven Plugin

    Use o upload-singleobjetivo :

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

    O uso de Wagon Maven Pluginpara copiar é direto e parece ser o mais versátil.


Nos exemplos acima, <url>pode ser de qualquer protocolo suportado. Veja a lista de fornecedores de vagões existentes . Por exemplo

  • copiando arquivo localmente: file:///copy/to
  • copiando o arquivo para o host remoto em execução SSH:scp://host:22/copy/to


Os exemplos acima passam os parâmetros do plug-in na linha de comando. Como alternativa, os plugins podem ser configurados diretamente no POM. Então a invocação será simplesmente comomvn deploy:deploy-file@configured-execution-id . Ou pode ser associado a uma fase de construção específica.


Observe que, para protocolos como o SCPtrabalho, você precisará definir uma extensão no seu POM:

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


Se o destino para o qual você está copiando exigir autenticação, as credenciais poderão ser fornecidas por meio de Serverconfigurações . repositoryId/ serverIdpassado para os plugins deve corresponder ao servidor definido nas configurações.

ᄂ ᄀ
fonte
3

Só posso supor que sua propriedade $ {project.server.config} seja algo personalizado definido e esteja fora do layout de diretório padrão.

Nesse caso, usaria a tarefa de cópia.

baleia
fonte
Digamos que eu tenha o cuidado de colocar os arquivos no layout de diretório padrão. O Maven pode copiá-los para o destino como estão, não em um zip / jar?
21009 Joshua Fox
2

Outra maneira é agrupar essas coisas em um artefato usando o plug-in de montagem. Em seguida, você pode usar o plug-in de dependência para descompactar esses arquivos onde desejar. Também existem metas de cópia no plug-in de dependência para copiar artefatos.

Brian Fox
fonte
1

Consegui reunir várias fontes diferentes para esta resposta:

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

Em seguida, execute o comando: (o -X é para depuração)

mvn -X upload:upload

Brett Dutton
fonte
-1

Para resumir algumas das respostas acima: O Maven foi projetado para criar módulos e copiar os resultados em um repositório do Maven. Qualquer cópia de módulos em um diretório de implantação / entrada de instalação deve ser feita fora do contexto da funcionalidade principal do Maven, por exemplo, com o comando Ant / Maven copy .

Joshua Fox
fonte
Ant pertence à funcionalidade principal do Maven e o Wagon (embora o plug-in ao redor dele não seja um plug-in oficial do Maven).
GeroldBroser restabelece Monica