如何从 Maven 存储库中清除旧的依赖项?
Posted
技术标签:
【中文标题】如何从 Maven 存储库中清除旧的依赖项?【英文标题】:How to clean old dependencies from maven repositories? 【发布时间】:2013-10-19 02:12:03 【问题描述】:我在 .m2 文件夹中有太多文件,maven 存储下载的依赖项。有没有办法清理所有旧的依赖项?例如,如果存在具有 3 个不同版本的依赖项:1、2 和 3,则清理后必须只有 3rd。我如何为 .m2 文件夹中的所有依赖项执行此操作?
【问题讨论】:
只需删除.m2repository
文件夹。编译项目后,它将自动创建。
或者买更大的硬盘,不在乎:)
可能有比等待编译和花钱买硬盘更优雅的解决方案吗? :) 但是说真的,我在虚拟机上远程工作,所以磁盘空间(小)和编译时间(长)很重要。这就是为什么我不能简单地更换硬盘或处理器。所以我需要一种更有效地使用它的方法。
如果您打开了 IDE 以及您最近的所有项目,文件系统锁定将阻止您删除正在使用的 jars
如何通过pom文件实现依赖的清理?
【参考方案1】:
问这个问题已经 6 年多了,但我仍然没有找到任何工具来令人满意地清理我的存储库。所以我自己用 Python 写了一个来摆脱旧的本地人工制品。也许它对其他人也有用:
repo-cleaner.py
:
from os.path import isdir
from os import listdir
import shutil
import semver
import Constants
# Change to True to get a log of what will be removed
dry_run = False
def check_and_clean(path):
files = listdir(path)
only_files = True
for index, file in enumerate(files):
if isdir('/'.join([path, file])):
only_files = False
else:
files[index] = None
if only_files:
return
directories = [d for d in files if d is not None]
latest_version = check_if_versions(directories)
if latest_version is None:
for directory in directories:
check_and_clean('/'.join([path, directory]))
elif len(directories) == 1:
return
else:
print('Update ' + path.split(Constants.m2_path)[1])
for directory in directories:
if directory == latest_version:
continue
print(directory + ' (Has newer version: ' + latest_version + ')')
if not dry_run:
shutil.rmtree('/'.join([path, directory]))
def check_if_versions(directories):
if len(directories) == 0:
return None
latest_version = ''
for directory in directories:
try:
current_version = semver.VersionInfo.parse(directory)
except ValueError:
return None
if latest_version == '':
latest_version = directory
if current_version.compare(latest_version) > 0:
latest_version = directory
return latest_version
if __name__ == '__main__':
check_and_clean(Constants.m2_path)
Constants.py
(编辑以指向您自己的本地 Maven 存储库):
# Paths
m2_path = '/home/jb/.m2/repository/'
确保您已安装 Python 3.6+,并且已将 semver 包安装到您的全局环境或 venv
(如果缺少,请使用 pip install semver
)。
使用python repo-cleaner.py
运行脚本。
它会在您配置的本地 Maven 存储库中递归搜索(通常为 ~/.m2/repository
),如果找到不同版本所在的目录,则会删除所有版本,但最新版本除外。
假设您在本地 Maven 存储库中的某处有以下树:
.
└── antlr
├── 2.7.2
│ ├── antlr-2.7.2.jar
│ ├── antlr-2.7.2.jar.sha1
│ ├── antlr-2.7.2.pom
│ ├── antlr-2.7.2.pom.sha1
│ └── _remote.repositories
└── 2.7.7
├── antlr-2.7.7.jar
├── antlr-2.7.7.jar.sha1
├── antlr-2.7.7.pom
├── antlr-2.7.7.pom.sha1
└── _remote.repositories
然后脚本删除antlr
的2.7.2版本,剩下的是:
.
└── antlr
└── 2.7.7
├── antlr-2.7.7.jar
├── antlr-2.7.7.jar.sha1
├── antlr-2.7.7.pom
├── antlr-2.7.7.pom.sha1
└── _remote.repositories
任何旧版本,即使是您积极使用的版本,都将被删除。它可以使用 Maven(或其他管理依赖项的工具)轻松恢复。
通过设置dry_run = True
,您可以在不实际删除的情况下获取将要删除的内容的日志。输出将如下所示:
update /org/projectlombok/lombok
1.18.2 (newer version: 1.18.6)
1.16.20 (newer version: 1.18.6)
这意味着 lombok 的 1.16.20 和 1.18.2 版本将被删除,而 1.18.6 将保持不变。
以上文件的最新版本可以在我的github找到。
【讨论】:
@ᴠɪɴᴄᴇɴᴛ 是的,脚本非常简化,因为它只在一个场景中为我服务。感谢您在拉取请求中改进它,因为这是您的工作,您也想编辑答案吗?【参考方案2】:我确实花了几个小时研究这个问题和答案,其中许多都依赖于atime
(这是 UNIX 系统上的最后访问时间),这是一个不可靠的解决方案,原因有两个:
-
大多数 UNIX 系统(包括 Linux 和 macOS)最多不定期更新
atime
,这是有原因的:atime
的完整实现意味着整个文件系统将因必须更新而变慢(即写入磁盘)atime
每次读取文件时,此外,如此极端数量的更新会很快磨损现代的高性能 SSD 驱动器
在 CI/CD 环境中,用于构建 Maven 项目的 VM 将从共享存储中恢复其 Maven 存储库,这反过来又会将 atime
设置为“最近”值
因此,我创建了一个 Maven 存储库清理器,并在 https://github.com/alitokmen/maven-repository-cleaner/ 上提供了它。 bash maven-repository-cleaner.sh
脚本有一个函数 cleanDirectory
,它是一个循环遍历 ~/.m2/repository/
的递归函数,并执行以下操作:
在实践中,如果您有如下层次结构:
artifact-group
artifact-name
1.8
1.10
1.2
...maven-repository-cleaner.sh
脚本将:
-
导航到
artifact-group
在artifact-group
中,导航到artifact-name
在artifact-name
中,删除子文件夹1.8
和1.2
,因为1.10
优于1.2
和1.8
因此这与Andronicus 和Pavan Kumar 提供的解决方案非常相似,不同之处在于它是作为Shell 脚本编写的。要在您的 CI/CD 平台(或任何其他形式的 UNIX 系统)上运行该工具,只需在构建开始或结束时使用以下三行:
wget https://raw.githubusercontent.com/alitokmen/maven-repository-cleaner/main/maven-repository-cleaner.sh
chmod +x maven-repository-cleaner.sh
./maven-repository-cleaner.sh
【讨论】:
【参考方案3】:给定一个 maven 项目的 POM 文件,您可以使用 Apache Maven Dependency Plugin 删除其在本地存储库(默认为 ~/.m2/respository)中的所有依赖项。
它包含dependency:purge-local-repository
功能,可从本地存储库中删除项目依赖项,并可选择重新解析它们。
要清理本地依赖项,您只需使用可选参数 reResolve 并将其设置为 false,因为它默认设置为 true。
这个命令行调用应该可以工作:
mvn dependency:purge-local-repository -DreResolve=false
【讨论】:
好 :) 但是这种清理依赖仅适用于当前项目,而不是所有存储库。 这是真的!为了清理整个存储库,我将手动从 ./m2/repository 中删除目录,正如之前或在较新版本的 Nexus(2.6.4-02 之后)中所评论的那样。它们提供了计划任务 link 从存储库中删除版本功能盒子外面。它也可能有用【参考方案4】:您需要复制项目所需的依赖项。
有了这些,请清除嵌入到<dependencies>
标签中的所有<dependency>
标签
来自项目中的 POM.XML 文件。
保存文件后,您将不会在 Libraries
中看到 Maven 依赖项。
然后请粘贴您之前复制的那些<dependency>
。
需要的 jars 会被 Maven 自动下载,你也可以在
保存文件后生成的Maven Dependencies Libraries
。
谢谢。
【讨论】:
【参考方案5】:我想出了一个实用程序并托管在 GitHub 上,用于清理本地 Maven 存储库中的旧版本库。该实用程序在默认执行时会删除所有旧版本的工件,只留下最新版本。可选地,它可以删除所有快照、源、javadocs,并且可以在此过程中强制/排除组或工件。此跨平台还支持基于上次访问/下载日期的基于日期的删除。
https://github.com/techpavan/mvn-repo-cleaner
【讨论】:
【参考方案6】:简答 -
删除了user.home
中的 .m2 文件夹。例如。在 Windows 10 用户主页中是 C:\Users\user1
。使用mvn clean package
重新构建您的项目。只有那些项目需要的依赖项才会保留。
长答案 - .m2 文件夹就像一个普通文件夹,文件夹的内容是由不同的项目构建的。我认为没有办法自动找出哪个库是“旧的”。事实上,老是一个模糊的词。在项目中使用以前版本的库可能有很多原因,因此无法确定哪个未使用。
您所能做的就是删除 .m2 文件夹并重新构建所有项目,然后该文件夹将自动构建所有必需的库。
如果您只关心要在所有项目中使用的库的特定版本;重要的是项目的 pom 也应该更新到最新版本。即,如果不同的 POM 引用不同版本的库,则所有内容都将下载到 .m2 中。
【讨论】:
“因此无法确定哪个未使用”。我不需要这个决定,我只需要留下新版本。 然后删除 .m2 文件夹,然后确保所有项目在 pom.xml 中只有新版本的 jar 条目。重新构建项目。 .m2 文件夹将仅保留最新版本。delete .m2
它会导致删除所有依赖项并从非常慢的存储库中下载新的依赖项。
对于上述问题 - 一种适合所有人的解决方案 - 我们可以采用上述方式。对于缓慢的问题,我建议该项目应咨询本地存储库(一种组织中的产品存储库设置);如果无法从公共存储库下载。在某个时间点,建议最终将工件上传到本地存储库 - 如果它在所有项目中如此广泛使用。【参考方案7】:
下载项目的所有实际依赖项
find your-projects-dir -name pom.xml -exec mvn -f '' dependency:resolve
将本地 maven 存储库移动到临时位置
mv ~/.m2 ~/saved-m2
将保存的存储库中的所有文件 maven-metadata-central.xml* 重命名为 maven-metadata.xml*
find . -type f -name "maven-metadata-central.xml*" -exec rename -v -- 's/-central//' '' \;
要将本地存储库的修改副本设置为镜像,请创建目录 ~/.m2 和文件 ~/.m2/settings.xml,其内容如下(替换 user 使用您的用户名):
<settings>
<mirrors>
<mirror>
<id>mycentral</id>
<name>My Central</name>
<url>file:/home/user/saved-m2/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
再次解决您的项目依赖关系:
find your-projects-dir -name pom.xml -exec mvn -f '' dependency:resolve
现在您拥有本地 maven 存储库,其中包含最少的必要工件。从配置文件和文件系统中删除本地镜像。
【讨论】:
试过这个,仍然得到:“在当前项目和插件组 [org.apache.maven.plugins, org.codehaus.mojo] 中找不到前缀'依赖'的插件存储库 [local (/home/user/.m2/repository), mycentral (file:/home/user/saved-m2/)]"【参考方案8】:只需清理 .m2-->repository 文件夹下的所有内容。当你构建项目时,所有依赖项都会加载到这里。
在您的情况下,您的项目之前可能使用任何依赖项的旧版本,现在版本已升级。所以最好清理 .m2 文件夹并使用 mvn clean install 构建您的项目。
现在,最新版本模块的依赖项将下载到此文件夹中。
【讨论】:
除非您将旧版 jar 手动添加到存储库中,或者 Internet 上不再提供依赖项。这个答案有点危险……至少先备份!【参考方案9】:我也想从我的 Maven 存储库中删除旧的依赖项。我想过只运行弗洛里安的答案,但我想要一些我可以一遍又一遍地运行而不会记住很长的 linux sn-p 的东西,我想要一些具有一点可配置性的东西——更多的是一个程序,而不是一个链unix 命令,所以我采用了基本思想并将其制作成一个(相对较小的)Ruby 程序,它根据上次访问时间删除旧的依赖项。
它不会删除“旧版本”,但是由于您实际上可能有两个不同的活动项目,它们具有两个不同版本的依赖项,所以无论如何我都不会这样做。相反,就像 Florian 的回答一样,它删除了最近未访问过的依赖项。
如果你想尝试一下,你可以:
-
访问GitHub repository
克隆存储库,或下载源代码
可以选择检查代码以确保它不是恶意的
运行
bin/mvnclean
有一些选项可以覆盖默认的 Maven 存储库、忽略文件、设置阈值日期,但您可以在 GitHub 上的 README 中阅读这些选项。
在我完成更多工作后,我可能会在某个时候将它打包为 Ruby gem,如果您已经安装并运行了 Ruby,这将简化事情 (gem install mvnclean; mvnclean
)。
【讨论】:
很高兴听到这个消息。我想我应该费心把它变成宝石。 看来我说得太早了。我不知道这种模式——但一些罐子被删除了,尽管我知道我最近用过它们。但是,与此同时,一些人仍然存在。 嗯。好吧,如果你能给我更多的细节,我很乐意调查一下。如果你做到了这一点,请在 GitHub 上提交一个问题供我跟踪。似乎对我来说工作相当一致,但可能有一些特定于 Cygwin 的东西我需要研究,例如。您是否在同意之前查看了它输出的列表,或者它太长而不值得审查?如果您确实可以再次尝试,如果我将上次使用的日期添加到摘要中会有所帮助吗? (github.com/geoffreywiseman/mvnclean/issues/10) 是的,您可以添加一些选项来转储调试输出(jar:上次访问日期)...我已经订阅了您打开的问题。 已更新;看看这个问题,描述你的一些选择。【参考方案10】:如果您使用的是 Unix,则可以使用其中文件的访问时间。只需为您的文件系统启用访问时间,然后运行您想要保留依赖项的所有项目的干净构建,然后执行以下操作(未测试!):
find ~/.m2 -amin +5 -iname '*.pom' | while read pom; do parent=`dirname "$pom"`; rm -Rf "$parent"; done
这将找到最后一次访问超过 5 分钟的所有 *.pom 文件(假设您开始构建最多 5 分钟前)并删除它们的目录。
在 rm 之前添加“echo”以进行“试运行”。
【讨论】:
在 OSX 上(也可以在 GNU 工具上工作)find ~/.m2/repository/ -atime +30 -iname '*.pom' -print0 | while read -d '' -r pom; do echo rm -rf "$(dirname $pom)"; done
其中atime
以天为单位(与amin
以分钟为单位相比)
我在 OSX 上使用 find ~/.m2 -atime +1w -iname '*.pom' | while read pom; do parent=$(dirname "$pom"); rm -rf "$parent"; done
。应该在其他 unix 上也能正常工作:)
我刚刚爱上了“查找”以上是关于如何从 Maven 存储库中清除旧的依赖项?的主要内容,如果未能解决你的问题,请参考以下文章