web-dev-qa-db-fra.com

Comment gérez-vous efficacement les instantanés horodatés maven-3?

Maintenant que maven-3 a fait drop support pour la <uniqueVersion> false </uniqueVersion> pour les artefacts de snapshot, il semble que vous ayez vraiment besoin d'utiliser des SNAPSHOTS horodatés. Surtout m2Eclipse, qui utilise maven 3 en interne semble être affecté par lui, les instantanés de mise à jour ne fonctionnent pas lorsque les INSTANTANÉS ne sont pas uniques.

Il semblait préférable pratique avant de définir tous les instantanés sur uniqueVersion = false

Maintenant, il ne semble pas difficile de passer à la version horodatée, après tout, ils sont gérés par un référentiel Nexus central, qui est capable de supprimer les anciens instantanés dans des intervalles réguliers.

Le problème vient des postes de travail des développeurs locaux. Leur référentiel local se développe rapidement très grand avec des instantanés uniques.

Comment faire face à ce problème?

En ce moment, je vois les solutions possibles suivantes:

  • Demandez aux développeurs de purger le référentiel à intervalles réguliers (ce qui conduit à beaucoup de frustrations, car il faut beaucoup de temps pour supprimer et encore plus pour télécharger tout le nécessaire)
  • Configurez un script qui supprime tous les répertoires [~ # ~] snapshot [~ # ~] du référentiel local et demandez aux développeurs d'exécuter ce script de temps en temps (mieux que le premier, mais il faut encore un certain temps pour exécuter et télécharger les instantanés actuels)
  • utiliser la dépendance: plugin purge-local-repository (a des problèmes lors de l'exécution à partir d'Eclipse, en raison des fichiers ouverts, doit être exécuté à partir de chaque projet)
  • configurer Nexus sur chaque poste de travail et configurer un travail pour nettoyer les anciens instantanés (meilleur résultat, mais je ne veux pas maintenir plus de 50 serveurs Nexus, plus la mémoire est toujours limitée sur les postes de travail des développeurs)
  • cesser d'utiliser des INSTANTANÉS du tout

Quelle est la meilleure façon d'empêcher votre référentiel local de remplir votre espace disque dur?

Mise à jour:

Pour vérifier le beaviour et pour donner plus d'informations, je configure un petit serveur Nexus, construisez deux projets (a et b) et essayez:

une:

<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>de.glauche</groupId>
  <artifactId>a</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <distributionManagement>
    <snapshotRepository>
        <id>nexus</id>
        <name>nexus</name>
        <url>http://server:8081/nexus/content/repositories/snapshots</url>
    </snapshotRepository>
  </distributionManagement>

</project>

b:

<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>de.glauche</groupId>
  <artifactId>b</artifactId>
  <version>0.0.1-SNAPSHOT</version>
    <distributionManagement>
    <snapshotRepository>
        <id>nexus</id>
        <name>nexus</name>
        <url>http://server:8081/nexus/content/repositories/snapshots/</url>
    </snapshotRepository>
  </distributionManagement>
 <repositories>
    <repository>
        <id>nexus</id>
        <name>nexus</name>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <url>http://server:8081/nexus/content/repositories/snapshots/</url>
    </repository>
 </repositories>
  <dependencies>
    <dependency>
        <groupId>de.glauche</groupId>
        <artifactId>a</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

Maintenant, quand j'utilise maven et que je lance "deploy" sur "a", j'aurai

a-0.0.1-SNAPSHOT.jar
a-0.0.1-20101204.150527-6.jar
a-0.0.1-SNAPSHOT.pom
a-0.0.1-20101204.150527-6.pom

dans le référentiel local. Avec une nouvelle version d'horodatage chaque fois que j'exécute la cible de déploiement. La même chose se produit lorsque j'essaie de mettre à jour des instantanés à partir du serveur Nexus (fermez le projet "a", supprimez-le du référentiel local, créez "b")

Dans un environnement où de nombreux snapshots sont créés (pensez au serveur hudson ...), le dépôt local se remplit rapidement des anciennes versions

Mise à jour 2:

Pour tester comment et pourquoi cela échoue, j'ai fait d'autres tests. Chaque test est exécuté contre tout nettoyer (de/glauche est supprimé à la fois des machines et du nexus)

  • mvn deploy avec maven 2.2.1:

le référentiel local sur la machine A contient snapshot.jar + snapshot-timestamp.jar

MAIS: un seul pot horodaté dans nexus, les métadonnées se lisent:

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>de.glauche</groupId>
  <artifactId>a</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <timestamp>20101206.200039</timestamp>

      <buildNumber>1</buildNumber>
    </snapshot>
    <lastUpdated>20101206200039</lastUpdated>
  </versioning>
</metadata>
  • exécuter les dépendances de mise à jour (sur la machine B) dans m2Eclipse (m3 intégré final) -> le référentiel local a snapshot.jar + snapshot-timestamp.jar :(
  • exécuter l'objectif du package avec maven externe 2.2.1 -> le référentiel local a snapshot.jar + snapshot-timestamp.jar :(

Ok, essayez ensuite avec maven 3.0.1 (après avoir supprimé toutes les traces du projet a)

  • le référentiel local sur la machine A est plus beau, un seul pot non horodaté

  • un seul pot horodaté dans nexus, les métadonnées se lisent comme suit:

    de.glauche a 0.0.1-INSTANTANÉ

    <snapshot>
      <timestamp>20101206.201808</timestamp>
      <buildNumber>3</buildNumber>
    </snapshot>
    <lastUpdated>20101206201808</lastUpdated>
    <snapshotVersions>
      <snapshotVersion>
        <extension>jar</extension>
        <value>0.0.1-20101206.201808-3</value>
        <updated>20101206201808</updated>
      </snapshotVersion>
      <snapshotVersion>
        <extension>pom</extension>
        <value>0.0.1-20101206.201808-3</value>
        <updated>20101206201808</updated>
      </snapshotVersion>
    </snapshotVersions>
    
  • exécuter les dépendances de mise à jour (sur la machine B) dans m2Eclipse (m3 intégré final) -> le référentiel local a snapshot.jar + snapshot-timestamp.jar :(

  • exécuter l'objectif du package avec maven externe 2.2.1 -> le référentiel local a snapshot.jar + snapshot-timestamp.jar :(

Donc, pour récapituler: l'objectif de "déploiement" dans maven3 fonctionne mieux que dans 2.2.1, le référentiel local sur la machine à créer semble bien. Mais, le récepteur se retrouve toujours avec beaucoup de versions horodatées ...

Qu'est-ce que je fais mal ?

Mise à jour 3

J'ai également testé diverses autres configurations, d'abord remplacer Nexus par artificiel -> même comportement. Utilisez ensuite les clients linux maven 3 pour télécharger les instantanés à partir du gestionnaire de référentiel -> le référentiel local a toujours des instantanés horodatés :(

83
mglauche

Le <uniqueVersion> configuration appliquée aux artefacts qui ont été déployés (via mvn deploy) vers un référentiel Maven tel que Nexus.

Pour les supprimer de Nexus, vous pouvez facilement créer un travail automatisé pour purger le référentiel SNAPSHOT chaque jour. Il peut être configuré pour conserver un certain nombre de clichés ou les conserver pendant un certain temps. C'est super facile et fonctionne très bien.

Les artefacts dans le référentiel local sur une machine de développeur y parviennent à partir de l'objectif "installer" et n'utilisent pas ces horodatages ... ils continuent simplement à remplacer la seule et unique version INSTANTANÉE, sauf si vous incrémentez également le numéro de révision (par exemple 1.0.0- INSTANTANÉ à 1.0.1-INSTANTANÉ).

34
HDave

Ce plugin supprime les artefacts du projet du référentiel local. Utile pour ne conserver qu'une seule copie d'un grand instantané local.

<plugin>         
    <groupId>org.codehaus.mojo</groupId>         
    <artifactId>build-helper-maven-plugin</artifactId>         
    <version>1.7</version>         
    <executions>           
        <execution>             
            <id>remove-old-artifacts</id>             
            <phase>package</phase>             
            <goals>               
                <goal>remove-project-artifact</goal>             
            </goals>            
            <configuration>  
                <removeAll>true</removeAll><!-- When true, remove all built artifacts including all versions. When false, remove all built artifacts of this project version -->             
            </configuration>          
        </execution>         
    </executions>       
</plugin>
13
Cathy

Eh bien, je n'ai aimé aucune des solutions proposées. La suppression du cache maven augmente souvent considérablement le trafic réseau et ralentit le processus de génération. build-helper-maven-plugin n'aide qu'avec un seul artefact, je voulais une solution qui puisse purger tous les artefacts d'instantanés horodatés obsolètes du cache local en une seule commande simple. Après quelques jours de recherche, j'ai abandonné et j'ai décidé d'écrire un petit programme. Le programme final semble assez bien fonctionner dans notre environnement. J'ai donc décidé de le partager avec d'autres qui pourraient avoir besoin d'un tel outil. Les sources peuvent être extraites de github: https://github.com/nadestin/tools/tree/master/MavenCacheCleanup

7
yurinadestin

En ce qui concerne l'élément de référentiel distant de cela, je pense que les réponses précédentes qui discutent d'une purge des INSTANTANÉS sur un intervalle régulier fonctionneront. Mais personne n'a abordé la partie synchronisation de poste de travail de développeur local de votre question.

Nous n'avons pas encore commencé à utiliser Maven3, nous n'avons donc pas encore vu d'instantanés commencer à se développer sur les machines locales.

Mais nous avons eu différents problèmes avec m2Eclipse. Lorsque la "résolution de l'espace de travail" est activée et que le projet existe dans notre espace de travail, les mises à jour source nous gardent généralement sur le bord de la fuite. Mais nous avons constaté qu'il était très difficile d'obtenir m2Eclipse pour se mettre à jour avec les artefacts récemment publiés dans Nexus. Nous rencontrons des problèmes similaires au sein de notre équipe et c'est particulièrement problématique parce que nous avons un très grand graphique de projet ... il y a beaucoup de dépendances qui ne seront pas dans votre espace de travail mais qui feront publier des INSTANTANÉS fréquemment.

Je suis sûr que cela revient à un problème dans m2Eclipse où il ne gère pas les INSTANTANÉS exactement comme il se doit. Vous pouvez voir dans la console Maven dans Eclipse où m2Eclipse vous dit qu'il ignore la mise à jour d'un INSTANTANÉ récemment publié car il a une version en cache. Si vous effectuez un -U à partir d'une configuration d'exécution ou de la ligne de commande, Maven récupérera le changement de métadonnées. Mais une sélection "Mettre à jour les instantanés ..." devrait indiquer à m2Eclipse que Maven expire ce cache. Il ne semble pas être transmis. Il semble y avoir un bogue qui est déposé pour cela si vous êtes intéressé à voter pour cela: https://issues.sonatype.org/browse/MNGECLIPSE-2608

Vous en avez fait mention dans un commentaire quelque part.

La meilleure solution de contournement pour ce problème semble être que les développeurs purgent leurs postes de travail locaux lorsque les choses commencent à s'effondrer depuis m2Eclipse. Solution similaire à un problème différent ... D'autres ont signalé des problèmes avec Maven 2.2.1 et 3 supportant m2Eclipse, et j'ai vu la même chose.

J'espère que si vous utilisez Maven3, vous pouvez le configurer pour ne tirer que le dernier INSTANTANÉ, et le mettre en cache pendant la durée indiquée par le référentiel (ou jusqu'à ce que vous l'expiriez manuellement). Espérons que vous n'aurez pas besoin d'avoir un tas d'instantanés assis dans votre référentiel local.

C'est à moins que vous ne parliez d'un serveur de build qui effectue manuellement un mvn install sur eux. En ce qui concerne la façon d'empêcher les INSTANTANÉS de se développer sur un environnement comme un serveur de build, nous avons en quelque sorte esquivé cette balle en faisant en sorte que chaque build utilise son propre espace de travail et son référentiel local (bien que, dans Maven 2.2.1, certaines choses telles que Les POM semblent toujours sortir du référentiel ~/.m2 /) Les INSTANTANÉS supplémentaires ne restent vraiment que pour une seule construction, puis ils sont supprimés (et téléchargés à nouveau à partir de zéro). Nous avons donc vu que cette approche finit par consommer plus d'espace pour commencer, mais elle a tendance à rester plus stable que d'avoir tout résolu à partir d'un seul référentiel. Cette option (sur Hudson) est appelée "Utiliser le référentiel Maven privé" et se trouve sous le bouton Avancé de la section Générer sur les configurations de projet lorsque vous avez choisi de construire avec Maven. Voici la description de l'aide pour cette option:

Normalement, Hudson utilise le référentiel Maven local tel que déterminé par Maven - le processus exact semble être non documenté, mais c'est ~/.m2/repository et peut être remplacé par dans ~/.m2/settings.xml (voir la référence pour plus de détails .) Cela signifie normalement que tous les travaux exécutés sur le même nœud partagent un même référentiel Maven. L'avantage est que vous pouvez économiser de l'espace disque, mais l'inconvénient est que parfois ces versions peuvent interférer les unes avec les autres. Par exemple, vous risquez de ne pas réussir correctement les builds, simplement parce que vous disposez de toutes les dépendances dans votre référentiel local, malgré le fait qu'aucun des référentiels de POM ne les possède.

Il existe également des problèmes signalés concernant le fait que des processus Maven simultanés tentent d'utiliser le même référentiel local.

Lorsque cette option est cochée, Hudson dira à Maven d'utiliser $ WORKSPACE/.repository comme référentiel Maven local. Cela signifie que chaque travail aura son propre référentiel Maven isolé juste pour lui-même. Il résout les problèmes ci-dessus, au détriment de la consommation d'espace disque supplémentaire.

Lorsque vous utilisez cette option, envisagez de configurer un gestionnaire d'artefacts Maven afin de ne pas avoir à accéder trop souvent aux référentiels Maven distants.

Si vous préférez activer ce mode dans toutes les tâches Maven exécutées sur Hudson, reportez-vous à la technique décrite ici.

J'espère que cela vous aidera - si cela ne résout pas votre problème, faites-moi savoir où j'ai manqué.

2
cwash

Dans groovy , suppression de fichiers horodatés comme artifact-0.0.1-20101204.150527-6.jar peut être très simple:

root = 'path to your repository'

new File(root).eachFileRecurse {
  if (it.name.matches(/.*\-\d{8}\.\d{6}\-\d+\.[\w\.]+$/)) {
    println 'Deleting ' + it.name
    it.delete()
  }
}

Installez Groovy , enregistrez le script dans un fichier et planifiez l'exécution à chaque semaine, démarrez, connectez-vous, selon ce qui vous convient.

Ou, vous pouvez même câbler l'exécution dans la construction maven, en utilisant gmavenplus-plugin . Remarquez, comment l'emplacement du référentiel est-il défini par maven dans la propriété settings.localRepository puis lié via la configuration dans la variable repository:

  <plugin>
    <groupId>org.codehaus.gmavenplus</groupId>
    <artifactId>gmavenplus-plugin</artifactId>
    <version>1.3</version>
    <executions>
      <execution>
        <phase>install</phase>
        <goals>
          <goal>execute</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <properties>
        <property>
          <name>repository</name>
          <value>${settings.localRepository}</value>
        </property>
      </properties>
      <scripts>
        <script><![CDATA[
          new File(repository).eachFileRecurse {
            if (it.name.matches(/.*\-\d{8}\.\d{6}\-\d+\.[\w\.]+$/)) {
              println 'Deleting snapshot ' + it.getAbsolutePath()
              it.delete()
            }
          }
        ]]></script>
      </scripts>
    </configuration>
    <dependencies>
      <dependency>
        <groupId>org.codehaus.groovy</groupId>
        <artifactId>groovy-all</artifactId>
        <version>2.3.7</version>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </plugin>  
1
vnov

Ajoutez le paramètre suivant dans votre fichier POM

[~ # ~] pom [~ # ~]

<configuration>
<outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
</configuration>

https://maven.Apache.org/plugins/maven-dependency-plugin/copy-mojo.html

Exemple POM

<plugins>
      <plugin>
        <groupId>org.Apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
          <execution>
            <id>copy</id>
            <phase>package</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>3.8.1</version>
                  <type>jar</type>
                  <overWrite>false</overWrite>
                  <outputDirectory>${project.build.directory}/alternateLocation</outputDirectory>
                  <destFileName>optional-new-name.jar</destFileName>
                </artifactItem>
              </artifactItems>
              **<outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>**
              <outputDirectory>${project.build.directory}/wars</outputDirectory>
              <overWriteReleases>false</overWriteReleases>
              <overWriteSnapshots>true</overWriteSnapshots>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Configurer dans Jenkins:

// copy artifact 
copyMavenArtifact(artifact: "commons-collections:commons-collections:3.2.2:jar", outputAbsoluteArtifactFilename: "${pwd()}/target/my-folder/commons-collections.jar")
0
vaquar khan