Meilleures pratiques pour copier des fichiers avec Maven

193

J'ai des fichiers de configuration et divers documents que je souhaite copier de l'environnement de développement vers le répertoire de serveur de développement à l'aide de Maven2. Étrangement, Maven ne semble pas fort dans cette tâche.

Quelques options:

  • Utilisation simple d'une tâche de copie dans Maven
<copy file="src/main/resources/config.properties" tofile="${project.server.config}/config.properties"/>
  • Utilisez le plugin Ant pour exécuter la copie depuis Ant.

    • Construisez un artefact de type zip , à côté de l'artefact "principal" du POM qui est généralement de type jar , puis décompressez cet artefact du référentiel dans le répertoire cible.

    • plugin maven-resources , comme mentionné ci-dessous.

    • Plugin Maven Assembly - mais cela semble nécessiter beaucoup de définitions manuelles, quand je veux faire les choses simplement et "de façon conventionnelle".

    • Cette page montre même comment construire un plugin pour faire de la copie!

    • plugin maven-upload , comme mentionné ci-dessous.

    • maven-dependency-plugin avec copie , comme mentionné ci-dessous.


Tout cela semble inutilement ad hoc: Maven est censé exceller dans l'accomplissement de ces tâches standard sans chichis.

Aucun conseil?

Joshua Fox
la source
2
Maven est construit autour de l'idée d'un cycle de vie avec des phases, la copie de fichiers aléatoires vers une tâche serveur distante ne correspond pas vraiment à cela. Pensez toujours à votre projet dans son ensemble.
André
3
"Tout cela semble inutilement ad hoc: Maven est censé exceller dans l'accomplissement de ces tâches standard sans tracas." Ce que vous faites n'est pas une tâche standard en soi. Si votre artefact était une guerre / oreille, alors ce serait aussi simple que d'utiliser le plugin cargo (cargo.codehaus.org/Maven2+plugin#Maven2plugin-get…). Ce que vous décrivez semble très spécifique à la façon dont vous effectuez les déploiements et non aux déploiements de conteneurs d'applications Java standard. Maven n'est pas vraiment conçu pour gérer les activités de déploiement de temps sur des serveurs en direct - il est davantage adapté aux activités de création / développement.
whaley
67
@ André: J'entends cet argument encore et encore, mais désolé, c'est BS. Il n'y a rien de mal à penser le projet dans son ensemble, mais une partie de tout système de construction décent devrait être une fonctionnalité qui me permet d'accomplir la tâche X de manière simple, comme la copie de fichiers, et Maven ne peut pas le faire. Il y a une raison pour laquelle tant de projets sont apparus récemment qui embrassent le paradigme build-scripts-are-code (comme Gradle, SBT ou Buildr).
Matthias
Je recommanderais d'avoir un pom.xml pour construire les artefacts et un autre pour déployer un artefact donné.
Thorbjørn Ravn Andersen
Toutes les suggestions ci-dessus ne semblent toujours pas me permettre de copier un fichier spécifique d'un autre projet / artefact dans un projet maven. J'ai des fichiers sous src / main / folder dans un artefact qui devient un bocal et j'ai essayé d'utiliser le plugin maven de copie de dépendance mais je n'ai pas trouvé de moyen de dire quels fichiers je veux copier et j'obtiens le bocal entier fichier dans le fichier d'assemblage tout le temps. Toutes les autres suggestions ici, comme les ressources, ne semblent pas me permettre de spécifier un artefact plutôt que les ressources à l'intérieur du projet
Alexandre Thenorio

Réponses:

119

Ne craignez pas le plugin Antrun. Tout simplement parce que certaines personnes ont tendance à penser que Ant et Maven sont dans l'opposition, ils ne le sont pas. Utilisez la tâche de copie si vous devez effectuer une personnalisation unique inévitable:

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

En répondant à cette question, je me concentre sur les détails de ce que vous avez demandé. Comment copier un fichier? La question et le nom de la variable m'amènent à des questions plus vastes telles que: "Existe-t-il une meilleure façon de gérer le provisionnement du serveur?" Utilisez Maven comme système de génération pour générer un artefact déployable, puis effectuez ces personnalisations soit dans des modules séparés, soit ailleurs. Si vous avez partagé un peu plus de votre environnement de construction, il pourrait y avoir une meilleure façon - il existe des plugins pour provisionner un certain nombre de serveurs. Pourriez-vous attacher un assembly qui est décompressé à la racine du serveur? Quel serveur utilisez-vous?

Encore une fois, je suis sûr qu'il existe un meilleur moyen.

Tim O'Brien
la source
Le descripteur de tâche est-il désormais obsolète?
Matt
3
@Matt Oui, le taskparamètre est désormais obsolète ( Antrun Plugin ). Vous devriez utiliser à la targetplace (depuis la 1.5). Malheureusement, il existe des exemples qui mélangent cela; par exemple targetparamètre et version<1,5.
2011
Comment cela peut-il être la réponse acceptée? Il devrait y avoir une demande de changement à maven pour que la copie soit 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 est mal
la source
Merci @Peter, c'était utile. J'utilise maintenant l'objectif de ressources de copie de plugin de ressources au lieu d'Antrun. Ce dernier est en fait beaucoup plus simple et intuitif à définir, mais je ne pouvais pas l'obtenir (version 1.3) pour passer toutes les propriétés personnalisées Maven (définies dans la section <properties>) à antrun, j'ai donc basculé vers le plugin de ressources.
Cornel Masson
2
Je pensais que c'était la bonne réponse ... jusqu'à ce que je réalise que le plugin de ressources n'a pas de configuration de saut. Antrun est la voie à suivre.
Mike Post
Il ne devrait pas être difficile de créer un profil de saut. Je n'ai pas utilisé antrun, donc je ne peux pas dire ce qui est plus facile / meilleur
Vivek Chavda
40

Pour copier un fichier, utilisez:

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

Pour copier un dossier avec des sous-dossiers, utilisez la configuration suivante:

           <configuration>
              <outputDirectory>${basedir}/target-folder</outputDirectory>
              <resources>          
                <resource>
                  <directory>/source-folder</directory>
                  <filtering>true</filtering>
                </resource>
              </resources>              
            </configuration>  
Alexander Drobyshevsky
la source
Le filtrage dans Maven fait référence à l'interpolation de chaînes, donc j'omettre <filtering>d'empêcher les modifications indésirables, par exemple, dans les fichiers de script qui utilisent des ${...}variables.
GeroldBroser réintègre Monica le
20

Le plugin de dépendance maven m'a fait gagner beaucoup de temps à me consacrer aux tâches des fourmis:

<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 dépendance: la copie est documentend, et a des objectifs plus utiles comme décompresser.

Pneus
la source
3
Je n'ai pas utilisé Ant depuis des années et je ne veux pas commencer à le faire pour une chose aussi simple. Merci donc pour cette réponse.
Gustave
17

Pour une simple copie-tâches, je peux recommander copy-rename-maven-plugin . C'est simple et simple à utiliser:

<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 vous souhaitez copier plusieurs fichiers, remplacez la <sourceFile>...</destinationFile>pièce par

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

De plus, vous pouvez spécifier plusieurs exécutions en plusieurs phases si nécessaire, le deuxième objectif est "renommer", qui fait simplement ce qu'il dit tandis que le reste de la configuration reste le même. Pour plus d'exemples d'utilisation, reportez-vous à la page d' utilisation .

Remarque : ce plugin ne peut copier que des fichiers, pas des répertoires. (Merci à @ james.garriss d'avoir trouvé cette limitation.)

morten.c
la source
2
Bien que j'aime ce plugin, il est étonnant qu'il ne puisse pas copier les répertoires.
james.garriss
3
@ james.garriss Je n'étais pas au courant de cette limitation mais malheureusement vous avez raison. Je vais modifier cela dans ma réponse pour peut-être faire gagner du temps à certaines personnes.
morten.c
7

La solution de fourmi ci-dessus est la plus facile à configurer, mais j'ai eu de la chance en utilisant le plug-in maven-upload d'Atlassian. Je n'ai pas pu trouver de bonne documentation, voici comment je l'utilise:

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

Les variables comme "$ {jboss.host}" référencées ci-dessus sont définies dans mon ~ / .m2 / settings.xml et sont activées à l'aide des profils maven. Cette solution n'est pas limitée à JBoss, c'est juste ce que j'ai nommé mes variables. J'ai un profil pour dev, test et live. Donc, pour télécharger mon oreille sur une instance jboss dans un environnement de test, j'exécuterais:

mvn upload:upload -P test

Voici un extrait 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>
       ...

Remarques: Le référentiel Atlassian maven qui a ce plugin est ici: https://maven.atlassian.com/public/

Je recommande de télécharger les sources et de consulter la documentation à l'intérieur pour voir toutes les fonctionnalités du plugin.

"

Kyle Renfro
la source
5

Eh bien, maven n'est pas censé être bon pour effectuer de fines tâches granulaires, ce n'est pas un langage de script comme bash ou ant, il est plutôt déclaratif - vous dites - j'ai besoin d'une guerre ou d'une oreille, et vous l'obtenez. Cependant, si vous devez personnaliser l'apparence de la guerre ou de l'oreille à l'intérieur, vous avez un problème. Ce n'est tout simplement pas procédural comme fourmi, mais déclaratif. Cela a des avantages au début et pourrait avoir beaucoup d'inconvénients à la fin.

Je suppose que le concept initial était d'avoir de bons plugins, qui "fonctionnent", mais la réalité est différente si vous faites des choses non standard.

Cependant, si vous mettez suffisamment d'efforts dans vos poms et quelques plugins personnalisés, vous obtiendrez un environnement de construction bien meilleur comme avec ant par exemple (cela dépend de votre projet bien sûr, mais cela devient de plus en plus vrai pour les projets plus gros).

siddhadev
la source
4

J'ai eu une très bonne expérience avec le plugin copy-maven . Il a une syntaxe beaucoup plus pratique et concise par rapport au plugin maven-resources.

azerole
la source
8
Malheureusement, le plugin copy-maven n'est pas compatible avec maven 3.1.x
Hakan
2
Le problème de suivi de la compatibilité avec maven 3.1 est là: github.com/evgeny-goldin/maven-plugins/issues/10
koppor
Oubliez ce plugin ... Recherchez ses fourches
Kukeltje
4

Une façon générique de copier des fichiers arbitraires consiste à utiliser l' abstraction de transport Maven Wagon . Il peut gérer différentes destinations via des protocoles comme file, HTTP, FTP, SCPou WebDAV.

Il existe quelques plugins qui permettent de copier des fichiers via l'utilisation de Wagon. Les plus notables sont:

  • Plug-in de déploiement Maven prêt à l'emploi

    Voilà l' deploy-fileobjectif. Il est assez rigide mais peut faire le travail:

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

    L'inconvénient majeur de son utilisation Maven Deploy Pluginest qu'il est conçu pour fonctionner avec les référentiels Maven. Il suppose une structure et des métadonnées particulières. Vous pouvez voir que le fichier est placé sous foo/bar/1.0/file-1.0.extet que les fichiers de somme de contrôle sont créés. Il n'y a aucun moyen de contourner cela.

  • Plugin Wagon Maven

    Utilisez l' upload-singleobjectif :

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

    L'utilisation de Wagon Maven Pluginpour la copie est simple et semble être la plus polyvalente.


Dans les exemples ci-dessus, il <url>peut s'agir de n'importe quel protocole pris en charge. Consultez la liste des fournisseurs de wagons existants . Par exemple

  • copie locale du fichier: file:///copy/to
  • copie du fichier sur l'hôte distant en cours d'exécution SSH:scp://host:22/copy/to


Les exemples ci-dessus transmettent les paramètres du plugin dans la ligne de commande. Alternativement, les plugins peuvent être configurés directement dans POM. Ensuite, l'invocation sera simplement comme mvn deploy:deploy-file@configured-execution-id. Ou il peut être lié à une phase de construction particulière.


Veuillez noter que pour que les protocoles aiment SCPfonctionner, vous devrez définir une extension dans votre POM:

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


Si la destination vers laquelle vous copiez nécessite une authentification, des informations d'identification peuvent être fournies via les Serverparamètres . repositoryId/ serverIdtransmis aux plugins doit correspondre au serveur défini dans les paramètres.

ᄂ ᄀ
la source
3

Je peux seulement supposer que votre propriété $ {project.server.config} est quelque chose de personnalisé et se situe en dehors de la disposition de répertoire standard.

Si oui, alors j'utiliserais la tâche de copie.

whaley
la source
Disons que je prends soin de mettre les fichiers dans la disposition de répertoire standard. Maven peut-il les copier tels quels dans la cible, pas dans un zip / pot?
Joshua Fox
2

Une autre façon consiste à regrouper ces éléments dans un artefact à l'aide du plugin d'assemblage. Ensuite, vous pouvez utiliser le plugin de dépendance pour décompresser ces fichiers où vous le souhaitez. Il existe également des objectifs de copie dans le plug-in de dépendance pour copier les artefacts.

Brian Fox
la source
1

J'ai pu rassembler un certain nombre de sources différentes pour cette réponse:

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

Exécutez ensuite la commande: (le -X est pour le débogage)

mvn -X upload:upload

Brett Dutton
la source
-1

Pour résumer certaines des bonnes réponses ci-dessus: Maven est conçu pour créer des modules et copier les résultats dans un référentiel Maven. Toute copie de modules dans un répertoire de déploiement / installateur doit être effectuée en dehors du contexte de la fonctionnalité principale de Maven, par exemple avec la commande Ant / Maven copy .

Joshua Fox
la source
Ant appartient à la fonctionnalité principale de Maven, tout comme Wagon (bien que le plugin qui l'entoure ne soit pas un plugin officiel Maven).
GeroldBroser réintègre Monica