Wie gehen Sie effizient mit Maven-3-Schnappschüssen mit Zeitstempel um?

86

Nachdem maven-3 die Unterstützung für die <uniqueVersion> false </ einzigartigVersion> für Snapshot-Artefakte eingestellt hat, müssen Sie anscheinend wirklich zeitgestempelte SNAPSHOTS verwenden. Insbesondere m2eclipse, das intern maven 3 verwendet, scheint davon betroffen zu sein. Update-Snapshots funktionieren nicht, wenn die SNAPSHOTS nicht eindeutig sind.

Es schien am besten Praxis , bevor alle Snapshots zu uniqueVersion = false gesetzt

Jetzt scheint es kein großes Problem zu sein, auf die zeitgestempelte Version zu wechseln, schließlich werden sie von einem zentralen Nexus-Repository verwaltet, das in der Lage ist, alte Schnappschüsse in regelmäßigen Intervallen zu löschen.

Das Problem sind die lokalen Entwicklerarbeitsplätze. Ihr lokales Repository wird mit einzigartigen Snapshots schnell sehr groß.

Wie gehe ich mit diesem Problem um?

Im Moment sehe ich die folgenden möglichen Lösungen:

  • Bitten Sie die Entwickler, das Repository in regelmäßigen Abständen zu löschen (was zu großer Aufregung führt, da das Löschen und das Herunterladen aller benötigten Dateien lange dauert).
  • Richten Sie ein Skript ein, das alle SNAPSHOT- Verzeichnisse aus dem lokalen Repository löscht, und bitten Sie die Entwickler, dieses Skript von Zeit zu Zeit auszuführen (besser als das erste, aber das Ausführen und Herunterladen aktueller Snapshots dauert noch einige Zeit).
  • Verwenden Sie das Plugin für die Abhängigkeit: purge-local-repository (Hat Probleme beim Ausführen von Eclipse, da geöffnete Dateien von jedem Projekt ausgeführt werden müssen).
  • Richten Sie Nexus auf jeder Workstation ein und richten Sie einen Job zum Bereinigen alter Snapshots ein (bestes Ergebnis, aber ich möchte nicht mehr als 50 Nexus-Server warten, und der Speicher auf Entwickler-Workstations ist immer knapp).
  • Verwenden Sie SNAPSHOTS überhaupt nicht mehr

Was ist der beste Weg, um zu verhindern, dass Ihr lokales Repository Ihren Festplattenspeicher ausfüllt?

Aktualisieren:

Um das Verhalten zu überprüfen und weitere Informationen zu geben, richte ich einen kleinen Nexus-Server ein, erstelle zwei Projekte (a und b) und versuche:

ein:

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

Wenn ich jetzt maven benutze und "deploy" auf "a" ausführe, habe ich

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

im lokalen Repository. Jedes Mal, wenn ich das Bereitstellungsziel ausführe, mit einer neuen Zeitstempelversion. Das gleiche passiert, wenn ich versuche, Snapshots vom Nexus-Server zu aktualisieren ("a" -Projekt schließen, aus dem lokalen Repository löschen, "b" erstellen)

In einer Umgebung, in der viele Schnappschüsse erstellt werden (denken Sie an Hudson Server ...), füllt sich das lokale Reposioty schnell mit alten Versionen

Update 2:

Um zu testen, wie und warum dies fehlschlägt, habe ich weitere Tests durchgeführt. Jeder Test wird gegen alles sauber ausgeführt (de / glauche wird sowohl von den Maschinen als auch vom Nexus gelöscht)

  • MVN-Bereitstellung mit Maven 2.2.1:

Das lokale Repository auf Computer A enthält snapshot.jar + snapshot-timestamp.jar

ABER: Nur ein Glas mit Zeitstempel im Nexus, Metadaten lauten:

<?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>
  • Führen Sie Update-Abhängigkeiten (auf Computer B) in m2eclipse (Embedded M3 Final) aus. -> Das lokale Repository verfügt über snapshot.jar + snapshot-timestamp.jar :(
  • Paketziel mit externem Maven ausführen 2.2.1 -> Das lokale Repository hat snapshot.jar + snapshot-timestamp.jar :(

Ok, nächster Versuch mit Maven 3.0.1 (nachdem alle Spuren von Projekt a entfernt wurden)

  • Das lokale Repository auf Maschine A sieht besser aus, nur ein Glas ohne Zeitstempel

  • Nur ein Glas mit Zeitstempel im Nexus, Metadaten lauten:

    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>

  • Führen Sie Update-Abhängigkeiten (auf Computer B) in m2eclipse (Embedded M3 Final) aus. -> Das lokale Repository verfügt über snapshot.jar + snapshot-timestamp.jar :(

  • Paketziel mit externem Maven ausführen 2.2.1 -> Das lokale Repository hat snapshot.jar + snapshot-timestamp.jar :(

Um es noch einmal zusammenzufassen: Das Ziel "Bereitstellen" in maven3 funktioniert besser als in 2.2.1. Das lokale Repository auf dem Erstellungscomputer sieht gut aus. Aber der Empfänger hat immer viele zeitgesteuerte Versionen ...

Was mache ich falsch ?

Update 3

Ich habe auch verschiedene andere Konfigurationen getestet und zuerst den Nexus durch künstliches -> gleiches Verhalten ersetzt. Verwenden Sie dann Linux Maven 3-Clients, um die Snapshots vom Repository-Manager herunterzuladen -> Das lokale Repository verfügt weiterhin über Snapshots mit Zeitstempel :(

mglauche
quelle
Verwandte Fragen, die sich nur auf den lokalen Teil .m2 \ repository beziehen und sich auf das lokale Repository auf einem (Jenkins) Build-Server konzentrieren: stackoverflow.com/q/9729076/223837 .
MarnixKlooster ReinstateMonica
Hier ist ein funktionierender Link zu den Apcahe Maven Comptability Notes - cwiki.apache.org/confluence/display/MAVEN/…
aka_sh

Antworten:

36

Die <uniqueVersion>Konfiguration wurde auf Artefakte angewendet, die (über mvn deploy) in einem Maven-Repository wie Nexus bereitgestellt wurden.

Um diese aus Nexus zu entfernen, können Sie einfach einen automatisierten Job erstellen, um das SNAPSHOT-Repository jeden Tag zu löschen. Es kann so konfiguriert werden, dass eine bestimmte Anzahl von Shapshots oder für einen bestimmten Zeitraum beibehalten wird. Es ist super einfach und funktioniert super.

Artefakte im lokalen Repository auf einem Entwicklercomputer gelangen vom Ziel "Installieren" dorthin und verwenden diese Zeitstempel nicht. Sie ersetzen lediglich die einzige SNAPSHOT-Version, es sei denn, Sie erhöhen auch die Versionsnummer (z. B. 1.0.0-). SNAPSHOT bis 1.0.1-SNAPSHOT).

HDave
quelle
1
Das Problem ist, dass das Ziel "Installieren" in einer verteilten Umgebung mit vielen Entwicklern nicht so häufig verwendet wird. Wir verwenden auch einen Hudson-Server, der bei jedem cvs-Commit neue Snapshots erstellt (und bereitstellt), was jeden Tag häufig vorkommt. Ich wusste über den Nexus-Snapshot-Löschmechanismus Bescheid, siehe Liste der möglichen Problemumgehungen.
mglauche
Jede Entwicklungsmaschine sollte ein "lokales" Repository haben ~/.m2/repositoryund jede pom.xmlsollte eine Repository-Definition haben, die auf eine einzelne Instanz von Nexus in Ihrem LAN verweist. (genau wie du zeigst). Wir haben dieses Setup zusammen mit Hudson, das auf jedem Subversion-Commit aufbaut und großartig funktioniert. SNAPSHOT-Builds werden in Nexus "bereitgestellt", wo sie gesammelt und wöchentlich gelöscht werden. Entwicklercomputer laden automatisch den neuesten SNAPSHOT von Nexus auf ~/.m2/repositoryherunter und ersetzen den zuvor heruntergeladenen. Entwickler sollten niemals eine eigene Nexus-Instanz haben.
HDave
2
Ich habe gerade Ihr Update gelesen und noch etwas hinzuzufügen: Die Artefakte mit Zeitstempel sollten niemals in Ihrem lokalen Repository (~ / .m2 / Repository) angezeigt werden. Wenn ja, stimmt etwas nicht. Sie sollten nur innerhalb von Nexus gesehen werden. Ja, in Nexus sammeln sie sich schnell. Möglicherweise Hunderte von MB pro Tag. Ein Nexus-Job kann diese täglich leichter löschen, um die Menge gering zu halten.
HDave
6
Sie landen definitiv im lokalen Repository (dem ~ / .m2 / Repository), sie landen dort, nachdem sie das Ziel "deploy" ausgeführt und bei mvn -U auf dem abhängigen Projekt (dh dem B-Projekt) installiert haben. Ich habe es sogar mit Maven 2.2.1 und Maven 3 getestet, beide haben das gleiche Verhalten.
mglauche
2
Ich glaube, ich verstehe es jetzt ... sie erscheinen NICHT dort, wenn die Entwicklung eine "Bereitstellung" durchführt, sondern wenn der Entwickler ein abhängiges Projekt erstellt. Zu diesem Zeitpunkt wird der neueste SNAPSHOT des Upstream-Projekts von Nexus in das ~ / .m2 / Repository heruntergeladen, wobei der Zeitstempel als Teil des Dateinamens intakt bleibt. Ist das richtig?
HDave
13

Dieses Plugin entfernt Projektartefakte aus dem lokalen Repository. Nützlich, um nur eine Kopie eines großen lokalen Schnappschusses aufzubewahren.

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

Nun, ich mochte keine der vorgeschlagenen Lösungen. Das Löschen des Maven-Cache erhöht häufig den Netzwerkverkehr erheblich und verlangsamt den Erstellungsprozess. Das Build-Helper-Maven-Plugin hilft nur bei einem Artefakt. Ich wollte eine Lösung, mit der alle veralteten Snapshot-Artefakte mit Zeitstempel in einem einfachen Befehl aus dem lokalen Cache entfernt werden können. Nach ein paar Tagen der Suche gab ich auf und beschloss, ein kleines Programm zu schreiben. Das endgültige Programm scheint in unserer Umgebung recht gut zu funktionieren. Deshalb habe ich beschlossen, es mit anderen zu teilen, die möglicherweise ein solches Tool benötigen. Quellen können aus Github abgerufen werden: https://github.com/nadestin/tools/tree/master/MavenCacheCleanup

Yurinadestin
quelle
@HDave Ich habe es nicht geschafft, das POM-Fragment hier richtig zu formatieren. Überprüfen Sie es unter https://github.com/nadestin/tools/wiki/m2cachecleanup-maven-plugin . Auf unseren Jenkins-Slaves beansprucht dieses Dienstprogramm täglich ~ 200 MB Festplattenspeicher.
Yurinadestin
2

Was das Remote-Repository betrifft, denke ich, dass die vorherigen Antworten, in denen das Löschen von SNAPSHOTs in regelmäßigen Abständen behandelt wird, funktionieren werden. Aber niemand hat den Teil der Synchronisierung der Workstation für lokale Entwickler in Ihrer Frage angesprochen.

Wir haben Maven3 noch nicht verwendet, daher müssen SNAPSHOTs noch auf lokalen Computern aufgebaut werden.

Wir hatten jedoch unterschiedliche Probleme mit m2eclipse. Wenn wir "Workspace Resolution" aktiviert haben und das Projekt in unserem Arbeitsbereich vorhanden ist, halten uns Quellaktualisierungen normalerweise auf dem neuesten Stand. Wir haben jedoch festgestellt, dass es sehr schwierig ist, m2eclipse dazu zu bringen, sich mit kürzlich veröffentlichten Artefakten in Nexus zu aktualisieren. Wir haben ähnliche Probleme in unserem Team und es ist besonders problematisch, weil wir ein sehr großes Projektdiagramm haben. Es gibt viele Abhängigkeiten, die nicht in Ihrem Arbeitsbereich vorhanden sind, aber häufig SNAPSHOTs veröffentlichen.

Ich bin mir ziemlich sicher, dass dies auf ein Problem in m2eclipse zurückzuführen ist, bei dem SNAPSHOTs nicht genau so behandelt werden, wie es sollte. Sie können in der Maven-Konsole in Eclipse sehen, wo m2eclipse Ihnen mitteilt, dass das Update eines kürzlich veröffentlichten SNAPSHOT übersprungen wird, da es eine zwischengespeicherte Version hat. Wenn Sie eine -U über eine Ausführungskonfiguration oder über die Befehlszeile ausführen, übernimmt Maven die Metadatenänderung. Eine Auswahl "Snapshots aktualisieren ..." sollte m2eclipse jedoch mitteilen, dass Maven diesen Cache ablaufen lässt. Es scheint nicht weitergegeben zu werden. Es scheint einen Fehler zu geben, der dafür gemeldet wird, wenn Sie daran interessiert sind, dafür zu stimmen: https://issues.sonatype.org/browse/MNGECLIPSE-2608

Sie haben dies irgendwo in einem Kommentar erwähnt.

Die beste Problemumgehung für dieses Problem scheint darin zu bestehen, dass Entwickler ihre lokalen Workstations bereinigen, wenn in m2eclipse Probleme auftreten. Ähnliche Lösung für ein anderes Problem ... Andere haben Probleme mit Maven 2.2.1 und 3 gemeldet, die m2eclipse unterstützen, und ich habe dasselbe gesehen.

Ich würde hoffen, wenn Sie Maven3 verwenden, können Sie es so konfigurieren, dass nur der neueste SNAPSHOT abgerufen wird, und diesen für die Zeit zwischenspeichern, die das Repository angibt (oder bis Sie es manuell ablaufen lassen). Hoffentlich müssen Sie dann nicht ein paar SNAPSHOTs in Ihrem lokalen Repository haben.

Es sei denn, Sie sprechen von einem Build-Server, der manuell a ausführt mvn installauf sie. Um zu verhindern, dass SNAPSHOTs in einer Umgebung wie einem Build-Server aufgebaut werden, sind wir dieser Aufzählung ausgewichen, indem jeder Build seinen eigenen Arbeitsbereich und sein eigenes lokales Repository verwendet (obwohl in Maven 2.2.1 bestimmte Dinge wie z POMs scheinen immer aus dem ~ / .m2 / Repository zu kommen.) Die zusätzlichen SNAPSHOTs bleiben wirklich nur für einen einzelnen Build erhalten und werden dann gelöscht (und von Grund auf neu heruntergeladen). Wir haben also gesehen, dass dieser Ansatz zunächst mehr Speicherplatz beansprucht, aber tendenziell stabiler bleibt, als wenn alles aus einem einzigen Repository heraus aufgelöst wird. Diese Option (auf Hudson) heißt "Privates Maven-Repository verwenden" und befindet sich unter der Schaltfläche "Erweitert" des Abschnitts "Erstellen" für Projektkonfigurationen, wenn Sie das Erstellen mit Maven ausgewählt haben. Hier ist die Hilfebeschreibung für diese Option:

Normalerweise verwendet Hudson das von Maven festgelegte lokale Maven-Repository - der genaue Prozess scheint nicht dokumentiert zu sein, aber es ist ~ / .m2 / repository und kann in ~ / .m2 / settings.xml überschrieben werden (weitere Informationen finden Sie in der Referenz .) Dies bedeutet normalerweise, dass alle Jobs, die auf demselben Knoten ausgeführt werden, ein einziges Maven-Repository gemeinsam nutzen. Der Vorteil davon ist, dass Sie Speicherplatz sparen können, aber der Nachteil ist, dass sich diese Builds manchmal gegenseitig stören können. Beispielsweise kann es sein, dass Builds falsch erfolgreich sind, nur weil Sie alle Abhängigkeiten in Ihrem lokalen Repository haben, obwohl keines der Repositorys in POM über diese verfügt.

Es gibt auch einige gemeldete Probleme im Zusammenhang mit gleichzeitigen Maven-Prozessen, die versuchen, dasselbe lokale Repository zu verwenden.

Wenn diese Option aktiviert ist, weist Hudson Maven an, $ WORKSPACE / .repository als lokales Maven-Repository zu verwenden. Dies bedeutet, dass jeder Job sein eigenes isoliertes Maven-Repository nur für sich selbst erhält. Es behebt die oben genannten Probleme auf Kosten des zusätzlichen Speicherplatzverbrauchs.

Wenn Sie diese Option verwenden, sollten Sie einen Maven-Artefakt-Manager einrichten, damit Sie nicht zu oft auf entfernte Maven-Repositorys zugreifen müssen.

Wenn Sie diesen Modus lieber in allen auf Hudson ausgeführten Maven-Jobs aktivieren möchten, lesen Sie die hier beschriebene Technik.

Hoffe, das hilft - wenn es Ihr Problem nicht behebt, lassen Sie mich bitte wissen, wo ich es verpasst habe.

cwash
quelle
Der oben erwähnte Fehler wurde behoben: bugs.eclipse.org/bugs/show_bug.cgi?id=339527
HDave
1

In Groovy kann das Löschen von zeitgestempelten Dateien wie artifact-0.0.1-20101204.150527-6.jarsehr einfach sein:

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()
  }
}

Installieren Sie Groovy , speichern Sie das Skript in einer Datei und planen Sie die Ausführung jede Woche, starten Sie, melden Sie sich an, was auch immer zu Ihnen passt.

Oder Sie können die Ausführung mit dem gmavenplus-Plugin sogar in einen Maven-Build verkabeln . Beachten Sie, wie der Repository-Speicherort von maven in die Eigenschaft festgelegt settings.localRepositoryund dann durch die Konfiguration in eine Variable gebunden wird 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
quelle
0

Fügen Sie Ihrer POM-Datei den folgenden Parameter hinzu

POM

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

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

POM Beispiel

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

In Jenkins konfigurieren:

// copy artifact 
copyMavenArtifact(artifact: "commons-collections:commons-collections:3.2.2:jar", outputAbsoluteArtifactFilename: "${pwd()}/target/my-folder/commons-collections.jar")
Vaquar Khan
quelle