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

86

Maintenant que maven-3 a supprimé la prise en charge de <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, update-snapshots ne fonctionne pas lorsque les SNAPSHOTS ne sont pas uniques.

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

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

Le problème, ce sont les postes de travail des développeurs locaux. Leur référentiel local devient rapidement très volumineux 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 frustration, 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 prend encore un certain temps à 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'éclipse, en raison de 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 restreinte sur les postes de travail des développeurs)
  • arrêter d'utiliser SNAPSHOTS du tout

Quelle est la meilleure façon d'empêcher votre dépôt local de remplir votre espace disque dur?

Mise à jour:

Pour vérifier le beaviour et pour donner plus d'informations, j'ai configuré 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 j'exécute "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'essaye de mettre à jour des instantanés à partir du serveur nexus (fermez "un" projet, supprimez-le du référentiel local, construisez "b")

Dans un environnement où beaucoup de clichés get build (pensez serveur hudson ...), la reposioty locale se remplit avec les anciennes versions rapides

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é des deux 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 (intégré m3 final) -> le référentiel local a snapshot.jar + snapshot-timestamp.jar :(
  • Lancer 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 meilleur, un seul fichier jar non horodaté

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

    de.glauche a 0.0.1-SNAPSHOT

    <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 (intégré m3 final) -> le référentiel local a snapshot.jar + snapshot-timestamp.jar :(

  • Lancer 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 "déployer" dans maven3 fonctionne mieux que dans 2.2.1, le référentiel local sur la machine de création semble bien. Mais, le récepteur se termine 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 le nexus par un artificiel -> même comportement. Ensuite, utilisez 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 :(

mglauche
la source
Question connexe, concernant uniquement la partie .m2 \ repository locale, axée sur le référentiel local sur un serveur de build (Jenkins): stackoverflow.com/q/9729076/223837 .
MarnixKlooster ReinstateMonica
Voici le lien de travail vers les notes de comptabilité d'Apcahe Maven - cwiki.apache.org/confluence/display/MAVEN/…
aka_sh

Réponses:

36

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

Pour les supprimer de Nexus, vous pouvez facilement créer une tâche automatisée pour purger le référentiel SNAPSHOT chaque jour. Il peut être configuré pour conserver un certain nombre de shapshots 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 arrivent à partir de l'objectif "installer" et n'utilisent pas ces horodatages ... ils continuent juste à remplacer la seule et unique version SNAPSHOT à moins que vous n'incrémentiez également le numéro de révision (par exemple 1.0.0- INSTANTANÉ à 1.0.1-INSTANTANÉ).

HDave
la source
1
Le problème est que l'objectif "installer" n'est pas tellement utilisé dans un environnement distribué avec de nombreux développeurs. Nous utilisons également un serveur hudson qui crée (et déploie) de nouveaux snapshots à chaque commit cvs, ce qui arrive assez souvent chaque jour. Je connaissais le mécanisme de suppression de snapshot nexus, voir la liste des solutions de contournement possibles.
mglauche
Chaque machine de développement doit avoir un référentiel «local» sous ~/.m2/repositoryet chacun pom.xmldoit avoir une définition de référentiel qui pointe vers une seule instance de Nexus sur votre LAN. (comme vous le montrez). Nous avons cette configuration, avec Hudson qui s'appuie sur chaque commit Subversion et cela fonctionne très bien. Les builds SNAPSHOT sont «déployés» sur Nexus où ils sont collectés et purgés chaque semaine. Les machines de développement téléchargent automatiquement le dernier SNAPSHOT de Nexus vers ~/.m2/repositoryet il remplace celui précédemment téléchargé. Les développeurs ne devraient jamais avoir leur propre instance Nexus.
HDave
2
Je viens de lire votre mise à jour et j'ai encore une chose à ajouter: les artefacts horodatés ne devraient jamais être vus dans votre référentiel local (~ / .m2 / repository). S'ils le sont, quelque chose ne va pas. Ils ne doivent être vus qu'à l'intérieur de Nexus. À l'intérieur de Nexus, oui, ils se rassemblent rapidement. Des centaines de Mo par jour potentiellement. Un travail nexus peut plus facilement les purger quotidiennement pour garder la petite quantité.
HDave
6
Ils finissent définitivement dans le référentiel local (le ~ / .m2 / repository), ils s'y retrouvent après avoir exécuté la cible «deploy» et sur mvn -U install sur le projet dépendant (c'est-à-dire le projet B). Je l'ai même testé avec maven 2.2.1 et maven 3, les deux ont le même comportement.
mglauche
2
Je pense que je comprends maintenant ... ils n'apparaissent PAS là quand le développeur fait un "déploiement", mais plutôt quand le développeur construit un projet dépendant. À ce moment-là, le dernier SNAPSHOT du projet en amont est téléchargé depuis Nexus vers le référentiel ~ / .m2 / avec l'horodatage laissé intact dans le nom du fichier. Est-ce correct?
HDave
13

Ce plugin supprime les artefacts du projet du référentiel local. Utile pour ne conserver qu'une seule copie du 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>
Cathy
la source
7

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 construction. build-helper-maven-plugin n'aide qu'avec un seul artefact, je voulais une solution capable de purger tous les artefacts de snapshot horodatés obsolètes du cache local en une seule commande. Après quelques jours de recherche, j'ai abandonné et j'ai décidé d'écrire un petit programme. Le programme final semble fonctionner assez bien dans notre environnement. J'ai donc décidé de le partager avec d'autres personnes qui pourraient avoir besoin d'un tel outil. Les sources peuvent être extraites de github: https://github.com/nadestin/tools/tree/master/MavenCacheCleanup

yourinadestin
la source
@HDave Je n'ai pas réussi à formater correctement le fragment pom ici, vérifiez-le sur https://github.com/nadestin/tools/wiki/m2cachecleanup-maven-plugin . Sur nos esclaves Jenkins, cet utilitaire récupère environ 200 Mo d'espace disque par jour.
yurinadestin
2

En ce qui concerne le dépôt distant, je pense que les réponses précédentes qui traitent d'une purge des SNAPSHOTs à intervalle régulier fonctionneront. Mais personne n'a abordé la partie de la synchronisation des postes de travail des développeurs locaux de votre question.

Nous n'avons pas encore commencé à utiliser Maven3, nous n'avons donc pas encore vu les SNAPSHOTs 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 des sources nous maintiennent généralement à la pointe de la technologie. Mais nous avons trouvé qu'il est très difficile de faire en sorte que m2eclipse se mette à jour avec des 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 car nous avons un très grand graphe de projet ... il y a beaucoup de dépendances qui ne seront pas dans votre espace de travail mais qui recevront des SNAPSHOTs publiés fréquemment.

Je suis presque sûr que cela revient à un problème dans m2eclipse où il ne gère pas les SNAPSHOTs exactement comme il se doit. Vous pouvez voir dans la console Maven dans eclipse où m2eclipse vous dit qu'il saute la mise à jour d'un SNAPSHOT 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. Cela ne semble pas être transmis. Il semble y avoir un bug là-bas qui est classé 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 à ce problème semble être de demander aux développeurs de purger leurs postes de travail locaux lorsque les choses commencent à se détériorer à partir de 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 SNAPSHOT et le mettre en cache pendant la durée indiquée par le référentiel (ou jusqu'à ce que vous l'expiriez à la main). J'espère que vous n'aurez pas besoin d'avoir un tas d'instantanés assis dans votre référentiel local.

À moins que vous ne parliez d'un serveur de build qui effectue manuellement un mvn installsur eux. En ce qui concerne la façon d'empêcher les SNAPSHOTs de se développer sur un environnement comme un serveur de build, nous avons en quelque sorte esquivé cette balle en demandant à chaque build d'utiliser 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 ~ / .m2 / repository) Les SNAPSHOTs 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 au départ, mais elle a tendance à rester plus stable que de tout résoudre à partir d'un seul référentiel. Cette option (sur Hudson) s'appelle «Utiliser le référentiel Maven privé» et se trouve sous le bouton Avancé de la section Construire 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 jobs exécutés sur le même nœud partagent un seul référentiel Maven. L'avantage de cela 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 pourriez finir par avoir des builds mal réussis, simplement parce que vous avez toutes les dépendances dans votre référentiel local, malgré le fait qu'aucun des référentiels de POM ne les a.

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 indiquera à Maven d'utiliser $ WORKSPACE / .repository comme référentiel Maven local. Cela signifie que chaque travail obtiendra son propre référentiel Maven isolé 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 tous les jobs Maven exécutés 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, veuillez me faire savoir où j'ai manqué.

cwash
la source
Le bogue mentionné ci-dessus a été corrigé: bugs.eclipse.org/bugs/show_bug.cgi?id=339527
HDave
1

Dans groovy , supprimer des fichiers horodatés comme artifact-0.0.1-20101204.150527-6.jarpeut ê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, ce qui vous convient.

Ou, vous pouvez même câbler l'exécution dans maven build, 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 à 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>  
vnov
la source
0

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 de 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")
vaquar khan
la source