Как эффективно работать со снимками maven-3 с отметками времени?

86

Теперь, когда maven-3 отказался от поддержки <uniqueVersion> false </uniqueVersion> для артефактов моментальных снимков, кажется, что вам действительно нужно использовать SNAPSHOTS с отметками времени. В частности, m2eclipse, который использует maven 3 внутри, кажется, затронут этим, снимки обновлений не работают, когда SNAPSHOTS не уникальны.

Раньше казалось лучшей практикой установить для всех снимков значение uniqueVersion = false.

Теперь, кажется, нет большой проблемы переключиться на версию с отметкой времени, в конце концов, они управляются центральным репозиторием nexus, который может удалять старые снимки через регулярные интервалы.

Проблема в местных рабочих станциях разработчиков. Их локальный репозиторий быстро становится очень большим с уникальными снимками.

Как справиться с этой проблемой?

Сейчас я вижу следующие возможные решения:

  • Попросите разработчиков регулярно очищать репозиторий (что приводит к большому разочарованию, так как удаление занимает много времени и еще больше времени для загрузки всего необходимого)
  • Настройте сценарий, который удаляет все каталоги SNAPSHOT из локального репозитория, и просите разработчиков время от времени запускать этот сценарий (лучше, чем первый, но все же требуется некоторое время для запуска и загрузки текущих снимков)
  • используйте плагин dependency: purge-local-repository (есть проблемы при запуске из eclipse из-за открытых файлов, необходимо запускать из каждого проекта)
  • настроить nexus на каждой рабочей станции и настроить задание по очистке старых снимков (лучший результат, но я не хочу поддерживать 50+ серверов nexus, плюс на рабочих станциях разработчиков всегда не хватает памяти)
  • прекратить использовать SNAPSHOTS вообще

Как лучше всего защитить локальный репозиторий от заполнения места на жестком диске?

Обновить:

Чтобы проверить поведение и получить дополнительную информацию, я настраиваю небольшой сервер нексуса, создаю два проекта (a и 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>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>

б:

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

Теперь, когда я использую maven и запускаю "deploy" на "a", у меня будет

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

в локальном репозитории. С новой версией отметки времени каждый раз, когда я запускаю цель развертывания. То же самое происходит, когда я пытаюсь обновить снимки с сервера nexus (закройте проект «a», удалите его из локального репозитория, создайте «b»)

В среде , где много снимков получить сборки (думает Hudson сервер ...), локальная reposioty заполняется со старыми версиями быстро

Обновление 2:

Чтобы проверить, как и почему это не удается, я провел еще несколько тестов. Каждый тест запускается для очистки всего (de / glauche удаляется как с машин, так и с нексуса)

  • mvn deploy с maven 2.2.1:

локальный репозиторий на машине A содержит файл snapshot.jar + snapshot-timestamp.jar

НО: только одна банка с меткой времени в нексусе, метаданные читают:

<?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>
  • запустить зависимости обновления (на машине B) в m2eclipse (встроенный m3 final) -> в локальном репозитории есть snapshot.jar + snapshot-timestamp.jar :(
  • запустить цель пакета с внешним maven 2.2.1 -> в локальном репозитории есть snapshot.jar + snapshot-timestamp.jar :(

Хорошо, следующая попытка с maven 3.0.1 (после удаления всех следов проекта a)

  • локальный репозиторий на машине A выглядит лучше, только одна банка без метки времени

  • только один jar с отметкой времени в нексусе, метаданные читают:

    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>
    

  • запустить зависимости обновления (на машине B) в m2eclipse (встроенный m3 final) -> в локальном репозитории есть snapshot.jar + snapshot-timestamp.jar :(

  • запустить цель пакета с внешним maven 2.2.1 -> в локальном репозитории есть snapshot.jar + snapshot-timestamp.jar :(

Итак, резюмируем: цель «развертывание» в maven3 работает лучше, чем в 2.2.1, локальный репозиторий на машине создания выглядит нормально. Но получатель всегда заканчивает с множеством версий с временными метками ...

Что я делаю не так ?

Обновление 3

Я также тестировал различные другие конфигурации, сначала заменил nexus на artifactory -> такое же поведение. Затем используйте клиенты linux maven 3 для загрузки снимков из диспетчера репозитория -> в локальном репозитории все еще есть снимки с отметкой времени :(

mglauche
источник
Связанный вопрос, касающийся только локальной части .m2 \ repository, ориентированной на локальный репозиторий на сервере сборки (Jenkins): stackoverflow.com/q/9729076/223837 .
MarnixKlooster ReinstateMonica
Вот рабочая ссылка на Apcahe Maven Comptability Notes - cwiki.apache.org/confluence/display/MAVEN/…
aka_sh

Ответы:

36

<uniqueVersion>Конфигурация применяется к артефактам , которые были развернуты (через MVN развертывания) в Maven хранилища , такие как Nexus.

Чтобы удалить их из Nexus, вы можете легко создать автоматическое задание для ежедневной очистки репозитория SNAPSHOT. Его можно настроить на сохранение определенного количества шепшотов или на сохранение их в течение определенного периода времени. Это очень просто и отлично работает.

Артефакты в локальном репозитории на машине разработчика попадают туда из цели «установить» и не используют эти временные метки ... они просто продолжают заменять единственную и неповторимую версию SNAPSHOT, если вы также не увеличиваете номер версии (например, 1.0.0- SNAPSHOT в 1.0.1-SNAPSHOT).

HDave
источник
1
Проблема в том, что цель «установить» не так часто используется в распределенной среде со многими разработчиками. Мы также используем сервер Hudson, который создает (и развертывает) новые снимки состояния при каждой фиксации cvs, что происходит довольно часто каждый день. Я знал о механизме удаления снимка нексуса, см. Список возможных обходных путей.
mglauche
На каждой машине разработки должен быть «локальный» репозиторий, ~/.m2/repositoryи каждая pom.xmlдолжна иметь определение репозитория, указывающее на один экземпляр Nexus в вашей локальной сети. (прямо как вы показываете). У нас есть эта настройка вместе с Hudson, которая строится на каждом коммите Subversion, и она отлично работает. Сборки SNAPSHOT «развертываются» в Nexus, где они собираются и очищаются еженедельно. Машины разработчика автоматически загружают последний снимок SNAPSHOT с Nexus ~/.m2/repositoryи заменяют ранее загруженный. Разработчики никогда не должны иметь собственный экземпляр Nexus.
HDave
2
Я только что прочитал ваше обновление и хочу добавить еще кое-что: артефакты с отметками времени никогда не должны находиться внутри вашего локального (~ / .m2 / repository) репозитория. Если да, то что-то не так. Их следует видеть только внутри Nexus. Внутри Nexus да, быстро собираются. Потенциально сотни МБ в день. С помощью нексуса их можно легче очищать ежедневно, чтобы количество оставалось небольшим.
HDave
6
Они определенно попадают в локальный репозиторий (~ / .m2 / repository), они попадают туда после запуска цели «deploy» и при установке mvn -U в зависимом проекте (то есть в проекте B). Я даже тестировал его с maven 2.2.1 и maven 3, оба имеют одинаковое поведение.
mglauche
2
Думаю, теперь я понял ... они НЕ появляются там, когда разработка выполняет «развертывание», а скорее, когда разработчик создает зависимый проект. В это время последний SNAPSHOT восходящего проекта загружается из Nexus в репозиторий ~ / .m2 / с сохранением временной метки как части имени файла. Это правильно?
HDave
13

Этот плагин удаляет артефакты проекта из локального репозитория. Полезно хранить только одну копию большого локального снимка.

<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>
Кэти
источник
7

Что ж, мне не понравилось ни одно из предложенных решений. Удаление кеша maven часто значительно увеличивает сетевой трафик и замедляет процесс сборки. build-helper-maven-plugin помогает только с одним артефактом, мне нужно решение, которое может удалить все устаревшие артефакты моментальных снимков с метками времени из локального кеша с помощью одной простой команды. После нескольких дней поисков я сдался и решил написать небольшую программу. Финальная программа, похоже, неплохо работает в нашей среде. Поэтому я решил поделиться им с другими, кому может понадобиться такой инструмент. Исходники можно получить с github: https://github.com/nadestin/tools/tree/master/MavenCacheCleanup

Юринадестин
источник
@HDave Мне не удалось правильно отформатировать фрагмент pom здесь, проверьте его на https://github.com/nadestin/tools/wiki/m2cachecleanup-maven-plugin . На наших ведомых устройствах Jenkins эта утилита ежедневно освобождает ~ 200 МБ дискового пространства.
yurinadestin
2

Что касается части удаленного репозитория, я думаю, что предыдущие ответы, в которых обсуждается очистка SNAPSHOTs на регулярной основе, будут работать. Но никто не обратился к части вашего вопроса, касающейся синхронизации рабочих станций локального разработчика.

Мы еще не начали использовать Maven3, поэтому нам еще предстоит увидеть, как снимки SNAPSHOT начинают накапливаться на локальных машинах.

Но с m2eclipse у нас были другие проблемы. Когда у нас включено «Разрешение рабочего пространства» и проект существует в нашей рабочей области, обновления исходного кода обычно держат нас на передовой. Но мы обнаружили, что очень сложно заставить m2eclipse обновлять себя недавно опубликованными артефактами в Nexus. Мы сталкиваемся с аналогичными проблемами в нашей команде, и это особенно проблематично, потому что у нас очень большой график проекта ... есть много зависимостей, которые не будут в вашей рабочей области, но будут часто публиковать SNAPSHOTs.

Я почти уверен, что это восходит к проблеме в m2eclipse, где он не обрабатывает снимки в точности так, как должен. Вы можете увидеть в консоли Maven в eclipse, где m2eclipse сообщает вам, что он пропускает обновление недавно опубликованного SNAPSHOT, потому что у него есть кешированная версия. Если вы выполните -U из конфигурации запуска или из командной строки, Maven подхватит изменение метаданных. Но выбор «Обновить снимки ...» должен указать m2eclipse, что Maven должен истечь этот кеш. Похоже, это не проходит. Похоже, что для этого есть ошибка, если вы хотите проголосовать за нее: https://issues.sonatype.org/browse/MNGECLIPSE-2608

Вы упомянули об этом где-то в комментарии.

Лучшее решение этой проблемы - это очистить локальные рабочие станции разработчиков, когда что-то начинает ломаться в m2eclipse. Аналогичное решение другой проблемы ... Другие сообщали о проблемах с Maven 2.2.1 и 3, поддерживающими m2eclipse, и я видел то же самое.

Я надеюсь, что если вы используете Maven3, вы можете настроить его так, чтобы он извлекал только последний снимок SNAPSHOT и кэшировал его на время, указанное в репозитории (или пока вы не истечете его вручную). Надеюсь, тогда вам не понадобится куча снимков в вашем локальном репозитории.

Это если вы не говорите о сервере сборки, который вручную выполняет mvn installна них. Что касается того, как предотвратить создание снимков SNAPSHOT в среде, такой как сервер сборки, мы как бы избежали этой пули, заставив каждую сборку использовать свое собственное рабочее пространство и локальный репозиторий (хотя в Maven 2.2.1 некоторые вещи, такие как Кажется, что POM всегда выходят из репозитория ~ / .m2 /). Дополнительные снимки остаются только для одной сборки, а затем они сбрасываются (и загружаются снова с нуля). Итак, мы видели, что этот подход в конечном итоге занимает больше места, но он, как правило, остается более стабильным, чем когда все решается из одного репозитория. Этот параметр (на Hudson) называется «Использовать частный репозиторий Maven» и находится под кнопкой «Дополнительно» в разделе «Сборка» в конфигурациях проекта, когда вы выбрали сборку с помощью Maven. Вот справочное описание этой опции:

Обычно Hudson использует локальный репозиторий Maven, как определено Maven - точный процесс кажется недокументированным, но это ~ / .m2 / repository и его можно переопределить в ~ / .m2 / settings.xml (см. Ссылку для получения более подробной информации. .) Обычно это означает, что все задания, которые выполняются на одном узле, используют один репозиторий Maven. Достоинством этого является то, что вы можете сэкономить дисковое пространство, но недостатком является то, что иногда эти сборки могут мешать друг другу. Например, у вас может получиться некорректная сборка только потому, что у вас есть все зависимости в вашем локальном репозитории, несмотря на то, что ни в одном из репозиториев в POM они не могут быть.

Сообщается также о некоторых проблемах, связанных с одновременными процессами Maven, пытающимися использовать один и тот же локальный репозиторий.

Когда этот параметр отмечен, Хадсон скажет Maven использовать $ WORKSPACE / .repository в качестве локального репозитория Maven. Это означает, что каждое задание получит собственный изолированный репозиторий Maven только для себя. Он устраняет указанные выше проблемы за счет дополнительного использования дискового пространства.

При использовании этого параметра рассмотрите возможность настройки диспетчера артефактов Maven, чтобы вам не приходилось слишком часто обращаться к удаленным репозиториям Maven.

Если вы предпочитаете активировать этот режим во всех заданиях Maven, выполняемых на Hudson, обратитесь к методике, описанной здесь.

Надеюсь, это поможет - если это не решит вашу проблему, дайте мне знать, где я пропустил.

мыть
источник
Указанная выше ошибка исправлена: bugs.eclipse.org/bugs/show_bug.cgi?id=339527
HDave
1

В Groovy удаление файлов с отметками времени, например, artifact-0.0.1-20101204.150527-6.jarможет быть очень простым:

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

Установите Groovy , сохраните сценарий в файл и запланируйте его выполнение каждую неделю, запуск, вход в систему - все, что вам подходит.

Или вы даже можете подключить выполнение к сборке maven, используя gmavenplus-plugin . Обратите внимание, как maven устанавливает местоположение репозитория в свойство, settings.localRepositoryа затем связывает его через конфигурацию с переменной 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>  
внов
источник
0

Добавьте следующий параметр в свой файл POM

ПОМ

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

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

Пример 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>

Настроить в Jenkins:

// copy artifact 
copyMavenArtifact(artifact: "commons-collections:commons-collections:3.2.2:jar", outputAbsoluteArtifactFilename: "${pwd()}/target/my-folder/commons-collections.jar")
Вакуар Хан
источник