¿Cómo maneja las instantáneas con marca de tiempo maven-3 de manera eficiente?

86

Ahora que maven-3 eliminó el soporte para <uniqueVersion> false </uniqueVersion> para artefactos de instantáneas, parece que realmente necesita usar SNAPSHOTS con marca de tiempo. Especialmente m2eclipse, que usa maven 3 internamente parece verse afectado por él, las instantáneas de actualización no funcionan cuando las instantáneas no son únicas.

Parecía una buena práctica antes establecer todas las instantáneas en uniqueVersion = false

Ahora, no parece un gran problema cambiar a la versión con marca de tiempo, después de todo, son administrados por un repositorio central nexus, que puede eliminar instantáneas antiguas en intervalos regulares.

El problema son las estaciones de trabajo de los desarrolladores locales. Su repositorio local rápido aumenta muy grande con instantáneas únicas.

¿Cómo lidiar con este problema?

Ahora mismo veo las siguientes posibles soluciones:

  • Pida a los desarrolladores que depuren el repositorio a intervalos regulares (lo que genera mucha frustración, ya que lleva mucho tiempo eliminarlo e incluso más tiempo descargar todo lo necesario)
  • Configure un script que elimine todos los directorios SNAPSHOT del repositorio local y solicite a los desarrolladores que ejecuten ese script de vez en cuando (mejor que el primero, pero aún lleva bastante tiempo ejecutar y descargar las instantáneas actuales)
  • use la dependencia: plugin purge-local-repository (tiene problemas cuando se ejecuta desde eclipse, debido a archivos abiertos, debe ejecutarse desde cada proyecto)
  • configurar nexus en cada estación de trabajo y configurar un trabajo para limpiar instantáneas antiguas (el mejor resultado, pero no quiero mantener más de 50 servidores nexus, además de que la memoria siempre es escasa en las estaciones de trabajo de los desarrolladores)
  • dejar de usar SNAPSHOTS en absoluto

¿Cuál es la mejor manera de evitar que su repositorio local llene el espacio de su disco duro?

Actualizar:

Para verificar el beaviour y dar más información, configuro un pequeño servidor nexus, construyo dos proyectos (ayb) e intento:

una:

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

segundo:

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

Ahora, cuando uso maven y ejecuto "deploy" en "a", tendré

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

en el repositorio local. Con una nueva versión de marca de tiempo cada vez que ejecuto el destino de implementación. Lo mismo sucede cuando trato de actualizar Snapshots desde el servidor nexus (cerrar "a" Project, eliminarlo del repositorio local, construir "b")

En un entorno donde la gran cantidad de instantáneas consiguen acumulación (creo servidor Hudson ...), el reposioty locales se llena de versiones antiguas rápidas

Actualización 2:

Para probar cómo y por qué esto falla, hice algunas pruebas más. Cada prueba se ejecuta contra todo limpio (de / glauche se elimina de ambas máquinas y nexus)

  • Implementación de mvn con maven 2.2.1:

El repositorio local en la máquina A contiene snapshot.jar + snapshot-timestamp.jar

PERO: solo un jar con marca de tiempo en nexus, los metadatos dicen:

<?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>
  • ejecutar las dependencias de actualización (en la máquina B) en m2eclipse (m3 final incrustado) -> el repositorio local tiene snapshot.jar + snapshot-timestamp.jar :(
  • ejecutar el objetivo del paquete con maven externo 2.2.1 -> el repositorio local tiene snapshot.jar + snapshot-timestamp.jar :(

Ok, siguiente intento con maven 3.0.1 (después de eliminar todos los rastros del proyecto a)

  • el repositorio local en la máquina A se ve mejor, solo un jar sin marca de tiempo

  • solo un jar con marca de tiempo en nexus, los metadatos dicen:

    de.glauche a 0.0.1-INSTANTÁNEA

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

  • ejecutar las dependencias de actualización (en la máquina B) en m2eclipse (m3 final incrustado) -> el repositorio local tiene snapshot.jar + snapshot-timestamp.jar :(

  • ejecutar el objetivo del paquete con maven externo 2.2.1 -> el repositorio local tiene snapshot.jar + snapshot-timestamp.jar :(

Entonces, para recapitular: el objetivo de "implementación" en maven3 funciona mejor que en 2.2.1, el repositorio local en la máquina creadora se ve bien. Pero, el receptor siempre termina con muchas versiones cronometradas ...

Qué estoy haciendo mal ?

Actualización 3

También probé varias otras configuraciones, primero reemplacé nexus con artifactory -> mismo comportamiento. Luego use clientes linux maven 3 para descargar las instantáneas del administrador del repositorio -> el repositorio local todavía tiene instantáneas con marca de tiempo :(

mglauche
fuente
Pregunta relacionada, solo sobre la parte local .m2 \ repository, centrada en el repositorio local en un servidor de compilación (Jenkins): stackoverflow.com/q/9729076/223837 .
MarnixKlooster ReinstateMonica
Aquí está el enlace de trabajo a las Notas de compatibilidad de
aka_sh

Respuestas:

36

La <uniqueVersion>configuración aplicada a los artefactos que se implementaron (a través de la implementación de mvn) en un repositorio de Maven como Nexus.

Para eliminarlos de Nexus, puede crear fácilmente un trabajo automatizado para purgar el repositorio SNAPSHOT todos los días. Puede configurarse para retener una cierta cantidad de instantáneas o conservarlas durante un cierto período de tiempo. Es súper fácil y funciona muy bien.

Los artefactos en el repositorio local en una máquina de desarrollador llegan desde el objetivo de "instalación" y no usan estas marcas de tiempo ... simplemente siguen reemplazando la única versión SNAPSHOT a menos que también esté incrementando el número de revisión (por ejemplo, 1.0.0- SNAPSHOT a 1.0.1-SNAPSHOT).

HDave
fuente
1
El problema es que el objetivo de "instalar" no es tan útil en un entorno distribuido con muchos desarrolladores. También usamos un servidor hudson que construye (e implementa) nuevas instantáneas en cada confirmación de cvs, lo que ocurre con bastante frecuencia todos los días. Sabía sobre el mecanismo de eliminación de instantáneas nexus, consulte la lista de posibles soluciones.
mglauche
Cada máquina de desarrollo debe tener un repositorio "local" ~/.m2/repositoryy cada una pom.xmldebe tener una definición de repositorio que apunte a una única instancia de Nexus en su LAN. (como muestra). Tenemos esta configuración, junto con Hudson que se basa en cada confirmación de Subversion y funciona muy bien. Las compilaciones SNAPSHOT se "implementan" en Nexus, donde se recopilan y depuran semanalmente. Las máquinas de desarrollo descargan automáticamente el último SNAPSHOT de Nexus ~/.m2/repositoryy reemplaza el descargado previamente. Los desarrolladores nunca deben tener su propia instancia de Nexus.
HDave el
2
Acabo de leer su actualización y tengo una cosa más que agregar: los artefactos con marca de tiempo nunca deben verse dentro de su repositorio local (~ / .m2 / repository). Si es así, algo anda mal. Solo deben verse dentro de Nexus. Dentro de Nexus, sí, se acumulan rápidamente. Potencialmente, cientos de MB al día. Un trabajo de nexus puede eliminarlos más fácilmente a diario para mantener la cantidad pequeña.
HDave el
6
Definitivamente terminan en el repositorio local (el ~ / .m2 / repository uno), terminan allí después de ejecutar el destino "deploy" y en mvn -U install en el proyecto dependiente (es decir, el proyecto B). Incluso lo probé con maven 2.2.1 y maven 3, ambos tienen el mismo comportamiento.
mglauche
2
Creo que lo entiendo ahora ... NO aparecen allí cuando el desarrollador hace un "despliegue", sino cuando el desarrollador crea un proyecto dependiente. En ese momento, el último SNAPSHOT del proyecto ascendente se descarga desde Nexus al repositorio ~ / .m2 / con la marca de tiempo intacta como parte del nombre del archivo. ¿Es esto correcto?
HDave el
13

Este complemento elimina los artefactos del proyecto del repositorio local. Útil para mantener solo una copia de una instantánea local grande.

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

Bueno, no me gustó ninguna de las soluciones propuestas. Eliminar la caché de Maven a menudo aumenta significativamente el tráfico de la red y ralentiza el proceso de compilación. build-helper-maven-plugin solo ayuda con un artefacto, quería una solución que pudiera purgar todos los artefactos de instantáneas con marca de tiempo obsoletos de la memoria caché local con un simple comando. Después de unos días de búsqueda, me di por vencido y decidí escribir un pequeño programa. El programa final parece estar funcionando bastante bien en nuestro entorno. Entonces decidí compartirlo con otras personas que puedan necesitar dicha herramienta. Las fuentes se pueden extraer de github: https://github.com/nadestin/tools/tree/master/MavenCacheCleanup

yurinadestin
fuente
@HDave No logré formatear correctamente el fragmento pom aquí, compruébalo en https://github.com/nadestin/tools/wiki/m2cachecleanup-maven-plugin . En nuestros esclavos Jenkins, esta utilidad recupera ~ 200 Mb de espacio en disco al día.
yurinadestin
2

En cuanto a la parte del repositorio remoto de esto, creo que las respuestas anteriores que discuten una purga de SNAPSHOTs en un intervalo regular funcionarán. Pero nadie ha abordado la parte de su pregunta sobre la sincronización de la estación de trabajo del desarrollador local.

Todavía no hemos comenzado a usar Maven3, por lo que aún no hemos visto SNAPSHOTs comenzando a acumularse en las máquinas locales.

Pero hemos tenido diferentes problemas con m2eclipse. Cuando tenemos la "Resolución del área de trabajo" habilitada y el proyecto existe dentro de nuestro espacio de trabajo, las actualizaciones de fuentes generalmente nos mantienen a la vanguardia. Pero hemos descubierto que es muy difícil conseguir que m2eclipse se actualice con los artefactos publicados recientemente en Nexus. Estamos experimentando problemas similares dentro de nuestro equipo y es particularmente problemático porque tenemos un gráfico de proyecto muy grande ... hay muchas dependencias que no estarán en su espacio de trabajo, pero que se publicarán SNAPSHOT con frecuencia.

Estoy bastante seguro de que esto se reduce a un problema en m2eclipse en el que no maneja SNAPSHOT exactamente como debería. Puede ver en la consola de Maven dentro de eclipse donde m2eclipse le dice que se está saltando la actualización de un SNAPSHOT publicado recientemente porque tiene una versión en caché. Si hace una -U desde una configuración de ejecución o desde la línea de comando, Maven recogerá el cambio de metadatos. Pero una selección de "Actualizar instantáneas ..." debería indicarle a m2eclipse que Maven expire este caché. No parece que se esté transmitiendo. Parece haber un error que se archivó para esto si está interesado en votar por él: https://issues.sonatype.org/browse/MNGECLIPSE-2608

Mencionaste esto en un comentario en alguna parte.

La mejor solución para este problema parece ser que los desarrolladores depuren sus estaciones de trabajo locales cuando las cosas comiencen a fallar dentro de m2eclipse. Solución similar a un problema diferente ... Otros han informado problemas con Maven 2.2.1 y 3 m2eclipse de respaldo, y yo he visto lo mismo.

Espero que, si está utilizando Maven3, pueda configurarlo para que solo extraiga el último SNAPSHOT y lo almacene en caché durante el tiempo que dice el repositorio (o hasta que lo expire manualmente). Con suerte, entonces no necesitará tener un montón de SNAPSHOT en su repositorio local.

Eso es a menos que esté hablando de un servidor de compilación que está haciendo manualmente un mvn installen ellos. En cuanto a cómo evitar que SNAPSHOTs se acumule en un entorno como un servidor de compilación, hemos esquivado esa bala haciendo que cada compilación use su propio espacio de trabajo y repositorio local (aunque, en Maven 2.2.1, ciertas cosas como Parece que los POM siempre salen del repositorio ~ / .m2 /) Los SNAPSHOT adicionales realmente solo se quedan para una sola compilación y luego se eliminan (y se descargan nuevamente desde cero). Entonces, hemos visto que este enfoque termina consumiendo más espacio para empezar, pero tiende a permanecer más estable que tener todo resuelto desde un solo repositorio. Esta opción (en Hudson) se llama "Usar repositorio privado de Maven" y está debajo del botón Avanzado de la sección Compilar en configuraciones de proyectos cuando ha seleccionado compilar con Maven. Aquí está la descripción de ayuda para esa opción:

Normalmente, Hudson usa el repositorio local de Maven según lo determinado por Maven: el proceso exacto parece no estar documentado, pero es ~ / .m2 / repository y se puede anular en ~ / .m2 / settings.xml (consulte la referencia para obtener más detalles .) Esto normalmente significa que todos los trabajos que se ejecutan en el mismo nodo comparten un único repositorio de Maven. La ventaja de esto es que puede ahorrar espacio en el disco, pero la desventaja es que a veces esas compilaciones pueden interferir entre sí. Por ejemplo, puede terminar teniendo compilaciones incorrectamente correctas, solo porque tiene todas las dependencias en su repositorio local, a pesar del hecho de que ninguno de los repositorios en POM podría tenerlas.

También hay algunos problemas reportados con respecto a tener procesos Maven concurrentes que intentan usar el mismo repositorio local.

Cuando esta opción está marcada, Hudson le dirá a Maven que use $ WORKSPACE / .repository como el repositorio local de Maven. Esto significa que cada trabajo obtendrá su propio repositorio Maven aislado solo para sí mismo. Soluciona los problemas anteriores, a expensas del consumo adicional de espacio en disco.

Cuando use esta opción, considere configurar un administrador de artefactos Maven para que no tenga que acceder a los repositorios remotos de Maven con demasiada frecuencia.

Si prefiere activar este modo en todos los trabajos de Maven ejecutados en Hudson, consulte la técnica que se describe aquí.

Espero que esto ayude; si no soluciona su problema, avíseme dónde me perdí

lavar
fuente
El error mencionado anteriormente se ha corregido: bugs.eclipse.org/bugs/show_bug.cgi?id=339527
HDave
1

En groovy , eliminar archivos con marca de tiempo como artifact-0.0.1-20101204.150527-6.jarpuede ser muy 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()
  }
}

Instale Groovy , guarde el script en un archivo y programe la ejecución cada semana, comience, inicie sesión, lo que más le convenga.

O incluso puede conectar la ejecución a la compilación de maven, utilizando gmavenplus-plugin . Observe, ¿cómo se establece la ubicación del repositorio por maven en la propiedad settings.localRepositoryy luego se vincula a través de la configuración en 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
fuente
0

Agregue el siguiente parámetro en su archivo POM

POM

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

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

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

Configurar en Jenkins:

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