Como você lida com instantâneos com carimbo de data / hora maven-3 de maneira eficiente?

86

Agora que o maven-3 eliminou o suporte para <uniqueVersion> false </uniqueVersion> para artefatos de instantâneo, parece que você realmente precisa usar SNAPSHOTS com carimbo de data / hora. Especialmente m2eclipse, que usa maven 3 internamente parece ser afetado com ele, update-snapshots não funcionam quando os SNAPSHOTS não são únicos.

Antes, parecia uma prática recomendada definir todos os instantâneos como uniqueVersion = false

Agora, não parece um grande problema mudar para a versão com carimbo de data / hora, afinal eles são gerenciados por um repositório nexus central, que é capaz de deletar snapshots antigos em intervalos regulares.

O problema são as estações de trabalho do desenvolvedor local. Seu repositório local rapidamente cresce muito com instantâneos exclusivos.

Como lidar com esse problema?

No momento, vejo as seguintes soluções possíveis:

  • Peça aos desenvolvedores para limpar o repositório em intervalos regulares (o que leva a muita frustração, pois leva muito tempo para excluir e ainda mais para baixar tudo o que é necessário)
  • Configure algum script que exclua todos os diretórios SNAPSHOT do repositório local e peça aos desenvolvedores para executar esse script de vez em quando (melhor do que o primeiro, mas ainda leva algum tempo para executar e baixar os instantâneos atuais)
  • use a dependência: plug-in purge-local-repository (tem problemas quando executado a partir do eclipse, devido a arquivos abertos, precisa ser executado a partir de cada projeto)
  • configurar nexus em cada estação de trabalho e configurar um trabalho para limpar instantâneos antigos (melhor resultado, mas não quero manter mais de 50 servidores nexus, além disso, a memória está sempre apertada nas estações de trabalho do desenvolvedor)
  • pare de usar SNAPSHOTS em tudo

Qual é a melhor maneira de evitar que seu repositório local ocupe espaço no disco rígido?

Atualizar:

Para verificar o comportamento e fornecer mais informações, eu configurei um pequeno servidor Nexus, construa dois projetos (aeb) e tente:

uma:

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

Agora, quando eu usar o maven e executar "deploy" em "a", terei

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

no repositório local. Com uma nova versão de carimbo de data / hora cada vez que executo o destino de implantação. O mesmo acontece quando tento atualizar os Snapshots do servidor Nexus (feche o Projeto "a", exclua-o do repositório local, compilação "b")

Em um ambiente onde muitos instantâneos são construídos (pense no servidor hudson ...), o repositório local se enche de versões antigas rapidamente

Atualização 2:

Para testar como e por que isso está falhando, fiz mais alguns testes. Cada teste é executado para limpar tudo (de / glauche é excluído de ambas as máquinas e nexo)

  • mvn deploy com maven 2.2.1:

o repositório local na máquina A contém snapshot.jar + snapshot-timestamp.jar

MAS: apenas um jar com carimbo de data / hora no nexo, os metadados lêem:

<?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>
  • execute dependências de atualização (na máquina B) em m2eclipse (m3 final integrado) -> o repositório local tem snapshot.jar + snapshot-timestamp.jar :(
  • execute o objetivo do pacote com maven externo 2.2.1 -> o repositório local tem snapshot.jar + snapshot-timestamp.jar :(

Ok, próxima tentativa com maven 3.0.1 (depois de remover todos os vestígios do projeto a)

  • repositório local na máquina A parece melhor, apenas um jar sem registro de data e hora

  • apenas um jar com carimbo de data / hora no nexo, os metadados lêem:

    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>
    

  • execute dependências de atualização (na máquina B) em m2eclipse (m3 final integrado) -> o repositório local tem snapshot.jar + snapshot-timestamp.jar :(

  • execute o objetivo do pacote com maven externo 2.2.1 -> o repositório local tem snapshot.jar + snapshot-timestamp.jar :(

Então, para recapitular: o objetivo "implantar" no maven3 funciona melhor do que no 2.2.1, o repositório local na máquina de criação parece bom. Mas, o receptor sempre termina com muitas versões com data e hora ...

O que estou fazendo errado ?

Atualização 3

Eu também testei várias outras configurações, primeiro substitua nexus por artifactory -> mesmo comportamento. Em seguida, use os clientes Linux maven 3 para baixar os instantâneos do gerenciador de repositório -> o repositório local ainda tem instantâneos com carimbo de data / hora :(

mglauche
fonte
Pergunta relacionada, sobre apenas a parte local .m2 \ repository, focada no repositório local em um servidor de compilação (Jenkins): stackoverflow.com/q/9729076/223837 .
MarnixKlooster ReinstateMonica
Aqui está o link de trabalho para as notas de compatibilidade do Apcahe Maven - cwiki.apache.org/confluence/display/MAVEN/…
aka_sh

Respostas:

36

A <uniqueVersion>configuração aplicada a artefatos que foram implantados (via mvn deploy) em um repositório Maven como o Nexus.

Para removê-los do Nexus, você pode criar facilmente um trabalho automatizado para limpar o repositório SNAPSHOT todos os dias. Ele pode ser configurado para reter um certo número de shapshots ou mantê-los por um determinado período de tempo. É super fácil e funciona muito bem.

Artefatos no repositório local em uma máquina de desenvolvedor chegam lá a partir do objetivo "instalar" e não usam esses carimbos de data / hora ... eles apenas continuam substituindo a única versão do SNAPSHOT, a menos que você também esteja incrementando o número de revisão (por exemplo, 1.0.0- SNAPSHOT para 1.0.1-SNAPSHOT).

HDave
fonte
1
O problema é que o objetivo de "instalar" não é tanto uso em um ambiente distribuído com muitos desenvolvedores. Também usamos um servidor hudson que cria (e implanta) novos instantâneos em cada cvs commit, o que acontece com bastante frequência a cada dia. Eu sabia sobre o nexo snapshot delete mechainsm, consulte a lista de possíveis soluções alternativas.
mglauche
Cada máquina de desenvolvimento deve ter um repositório "local" ~/.m2/repositorye cada uma pom.xmldeve ter uma definição de repositório que aponta para uma única instância do Nexus em sua LAN. (assim como você mostra). Nós temos isso configurado, junto com o Hudson que se baseia em cada commit do Subversion e funciona muito bem. As compilações SNAPSHOT são "implementadas" no Nexus, onde são coletadas e eliminadas semanalmente. As máquinas do desenvolvedor baixam automaticamente o SNAPSHOT mais recente do Nexus para ~/.m2/repositorye ele substitui o anteriormente baixado. Os desenvolvedores nunca devem ter sua própria instância Nexus.
HDave
2
Acabei de ler sua atualização e tenho mais uma coisa a acrescentar: Os artefatos com carimbo de data / hora nunca devem ser vistos dentro de seu repositório local (~ / .m2 / repositório). Se estiverem, algo está errado. Eles só devem ser vistos dentro do Nexus. Dentro do Nexus, sim, eles coletam rapidamente. Potencialmente centenas de MBs por dia. Um trabalho de nexo pode eliminá-los mais facilmente diariamente para manter a quantidade pequena.
HDave
6
Eles definitivamente acabam no repositório local (o ~ / .m2 / repository), eles vão parar lá depois de executar o destino "deploy" e no mvn -U install no projeto dependente (ou seja, o projeto B). Eu até testei com o maven 2.2.1 e o maven 3, ambos têm o mesmo comportamento.
mglauche
2
Acho que entendi agora ... eles NÃO aparecem lá quando o desenvolvedor faz uma "implantação", mas sim quando o desenvolvedor cria um projeto dependente. Nesse momento, o SNAPSHOT mais recente do projeto upstream é baixado do Nexus para o repositório ~ / .m2 / com o carimbo de data / hora intacto como parte do nome do arquivo. Isto está certo?
HDave
13

Este plugin remove os artefatos do projeto do repositório local. Útil para manter apenas uma cópia de um grande instantâneo 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
fonte
7

Bem, eu não gostei de nenhuma das soluções propostas. A exclusão do cache do maven geralmente aumenta significativamente o tráfego de rede e retarda o processo de construção. build-helper-maven-plugin ajuda apenas com um artefato, eu queria uma solução que pudesse limpar todos os artefatos de instantâneo com carimbo de data / hora desatualizados do cache local em um comando simples. Após alguns dias de pesquisa, desisti e decidi escrever um pequeno programa. O programa final parece estar funcionando muito bem em nosso ambiente. Então, decidi compartilhar com outras pessoas que possam precisar dessa ferramenta. As fontes podem ser extraídas do github: https://github.com/nadestin/tools/tree/master/MavenCacheCleanup

yurinadestin
fonte
@HDave Não consegui formatar corretamente o fragmento de pom aqui, verifique em https://github.com/nadestin/tools/wiki/m2cachecleanup-maven-plugin . Em nossos escravos Jenkins, esse utilitário recupera ~ 200 MB de espaço em disco diariamente.
yurinadestin
2

Quanto à parte do repositório remoto disso, acho que as respostas anteriores que discutem uma limpeza de SNAPSHOTs em um intervalo regular funcionarão. Mas ninguém abordou a parte de sincronização da estação de trabalho do desenvolvedor local de sua pergunta.

Ainda não começamos a usar o Maven3, portanto, ainda não vimos SNAPSHOTs começando a se acumular nas máquinas locais.

Mas tivemos problemas diferentes com m2eclipse. Quando temos a "Resolução do espaço de trabalho" ativada e o projeto existe dentro do nosso espaço de trabalho, as atualizações de código-fonte geralmente nos mantêm atualizados. Mas descobrimos que é muito difícil fazer com que o m2eclipse se atualize com artefatos publicados recentemente no Nexus. Estamos enfrentando problemas semelhantes em nossa equipe e isso é particularmente problemático porque temos um gráfico de projeto muito grande ... há muitas dependências que não estarão em sua área de trabalho, mas obterão SNAPSHOTs publicados com frequência.

Tenho certeza de que isso volta a ser um problema no m2eclipse onde ele não lida com SNAPSHOTs exatamente como deveria. Você pode ver no console Maven dentro do eclipse onde m2eclipse diz que está pulando a atualização de um SNAPSHOT publicado recentemente porque tem uma versão em cache. Se você fizer um -U a partir de uma configuração de execução ou da linha de comando, o Maven pegará a mudança de metadados. Mas uma seleção "Atualizar instantâneos ..." deve informar ao m2eclipse para que o Maven expire este cache. Não parece estar sendo transmitido. Parece haver um bug arquivado para isso se você estiver interessado em votar nele: https://issues.sonatype.org/browse/MNGECLIPSE-2608

Você fez menção a isso em um comentário em algum lugar.

A melhor solução para esse problema parece ser fazer com que os desenvolvedores limpem suas estações de trabalho locais quando as coisas começarem a quebrar de dentro do m2eclipse. Solução semelhante para um problema diferente ... Outros relataram problemas com Maven 2.2.1 e 3 m2eclipse de apoio, e eu vi o mesmo.

Espero que, se você estiver usando o Maven3, você possa configurá-lo para obter apenas o SNAPSHOT mais recente e armazená-lo em cache pelo período de tempo que o repositório diz (ou até que você o expire manualmente). Com sorte, você não precisará ter um monte de SNAPSHOTs em seu repositório local.

A menos que você esteja falando sobre um servidor de compilação que está fazendo manualmente um mvn installneles. No que diz respeito a como evitar que SNAPSHOTs se acumulem em um ambiente como um servidor de compilação, meio que evitamos esse ponto fazendo com que cada compilação use seu próprio espaço de trabalho e repositório local (embora, no Maven 2.2.1, certas coisas como Os POMs parecem sempre sair do repositório ~ / .m2 /). Os SNAPSHOTs extras só ficam por aí em uma única construção e depois são descartados (e baixados novamente do zero). Portanto, vimos que essa abordagem acaba consumindo mais espaço para começar, mas tende a permanecer mais estável do que ter tudo resolvido em um único repositório. Esta opção (no Hudson) é chamada de "Usar repositório privado Maven" e está no botão Avançado da seção Construir nas configurações do projeto quando você selecionou construir com Maven. Aqui está a descrição de ajuda para essa opção:

Normalmente, Hudson usa o repositório Maven local conforme determinado pelo Maven - o processo exato parece não documentado, mas é ~ / .m2 / repository e pode ser substituído por em ~ / .m2 / settings.xml (consulte a referência para mais detalhes .) Isso normalmente significa que todos os trabalhos executados no mesmo nó compartilham um único repositório Maven. A vantagem disso é que você pode economizar espaço em disco, mas a desvantagem disso é que às vezes essas compilações podem interferir umas nas outras. Por exemplo, você pode acabar tendo compilações incorretamente bem-sucedidas, apenas porque você tem todas as dependências em seu repositório local, apesar do fato de que nenhum dos repositórios no POM pode tê-las.

Também há alguns problemas relatados em relação a processos Maven simultâneos tentando usar o mesmo repositório local.

Quando esta opção está marcada, Hudson dirá ao Maven para usar $ WORKSPACE / .repository como o repositório Maven local. Isso significa que cada trabalho obterá seu próprio repositório Maven isolado apenas para ele. Ele corrige os problemas acima, às custas do consumo adicional de espaço em disco.

Ao usar esta opção, considere configurar um gerenciador de artefatos Maven para que você não precise acessar repositórios Maven remotos com muita frequência.

Se você preferir ativar este modo em todos os jobs Maven executados no Hudson, consulte a técnica descrita aqui.

Espero que isso ajude - se não resolver o seu problema, me avise onde perdi.

cwash
fonte
O bug mencionado acima foi corrigido: bugs.eclipse.org/bugs/show_bug.cgi?id=339527
HDave
1

No groovy , excluir arquivos com carimbo de data / hora como artifact-0.0.1-20101204.150527-6.jarpode ser muito simples:

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 o Groovy , salve o script em um arquivo e agende a execução a cada semana, inicie, faça logon, o que for mais conveniente para você.

Ou você pode até conectar a execução à compilação do maven, usando o gmavenplus-plugin . Observe, como o local do repositório é definido pelo maven na propriedade settings.localRepositorye, em seguida, vinculado por meio da configuração à variável 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
fonte
0

Adicione o seguinte parâmetro em seu arquivo POM

POM

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

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

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

Configure no Jenkins:

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