我在 .m2 文件夹中有太多文件,Maven 存储下载的依赖项。有没有办法清理所有旧的依赖项?例如,如果存在具有 3 个不同版本的依赖项:1、2 和 3,则清理后必须只有 3rd。我如何为 .m2 文件夹中的所有依赖项执行此操作?
10 回答
如果您在 Unix 上,则可以使用其中文件的访问时间。只需为您的文件系统启用访问时间,然后运行您想要保留依赖项的所有项目的干净构建,然后执行以下操作(未测试!):
find ~/.m2 -amin +5 -iname '*.pom' | while read pom; do parent=`dirname "$pom"`; rm -Rf "$parent"; done
这将找到最后一次访问超过 5 分钟的所有 *.pom 文件(假设您最多在 5 分钟前开始构建)并删除它们的目录。
在 rm 之前添加“echo”以进行“试运行”。
简短回答- 已删除 .m2 文件夹中的{user.home}
. 例如,在 Windows 10 用户主页中是C:\Users\user1
. 使用mvn clean package
. 只有那些依赖项会保留,这是项目所需要的。
长答案- .m2 文件夹就像一个普通文件夹,文件夹的内容是从不同的项目构建的。我认为没有办法自动找出哪个库是“旧的”。事实上,老是一个模糊的词。在项目中使用以前版本的库时可能有很多原因,因此无法确定哪个未使用。
您所能做的就是删除 .m2 文件夹并重新构建所有项目,然后该文件夹将自动构建所有必需的库。
如果您只关心要在所有项目中使用的特定版本的库;重要的是项目的 pom 也应该更新到最新版本。即,如果不同的 POM 引用了不同版本的库,则所有内容都将以 .m2 格式下载。
给定一个 maven 项目的 POM 文件,您可以使用Apache Maven Dependency Plugin删除其在本地存储库(默认为 ~/.m2/respository)中的所有依赖项。
它包括dependency:purge-local-repository
从本地存储库中删除项目依赖项的功能,并可选择重新解析它们。
要清理本地依赖项,您只需使用可选参数reResolve并将其设置为 false,因为它默认设置为 true。
此命令行调用应该可以工作:
mvn dependency:purge-local-repository -DreResolve=false
下载项目的所有实际依赖项
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 (用您的用户名替换用户):
<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 存储库,其中包含最少的必要工件。从配置文件和文件系统中删除本地镜像。
问这个问题已经 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
然后脚本删除 2.7.2 版本,antlr
剩下的是:
.
└── 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上找到。
我想出了一个实用程序并托管在 GitHub 上,以清理本地 Maven 存储库中的旧版本库。该实用程序在默认执行时会删除所有旧版本的工件,只留下最新版本。可选地,它可以删除所有快照、源、javadocs,并且可以在此过程中强制/排除组或工件。此跨平台还支持基于上次访问/下载日期的基于日期的删除。
只需清理 .m2-->repository 文件夹下的所有内容。构建项目时,所有依赖项都会加载到此处。
在您的情况下,您的项目之前可能使用任何依赖项的旧版本,现在版本已升级。所以最好清理 .m2 文件夹并使用 mvn clean install 构建您的项目。
现在,具有最新版本模块的依赖项将下载到此文件夹中。
我确实花了几个小时来研究这个问题和答案,其中许多都依赖于atime
(这是 UNIX 系统上的最后访问时间),这是一个不可靠的解决方案,原因有两个:
- 大多数 UNIX 系统(包括 Linux 和 macOS)
atime
充其量不定期更新,这是有原因的:一个完整的实现意味着atime
整个文件系统将因必须更新(即写入磁盘)而减慢atime
读取文件的时间,此外,如此大量的更新会很快磨损现代的高性能 SSD 驱动器 - 在 CI/CD 环境中,用于构建 Maven 项目的 VM 将从共享存储恢复其 Maven 存储库,这反过来会将
atime
get 设置为“最近”值
因此,我创建了一个 Maven 存储库清理器,并在https://github.com/alitokmen/maven-repository-cleaner/上提供了它。bashmaven-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
and1.2
,as1.10
优于 both1.2
and1.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
我也想从我的 Maven 存储库中删除旧的依赖项。我想过只运行弗洛里安的答案,但我想要一些我可以一遍又一遍地运行而不会记住长长的 linux 片段的东西,我想要一些具有一点可配置性的东西——更多的是一个程序,而不是一个 unix 命令链,所以我采用了基本思想并将其制成一个(相对较小的)Ruby 程序,该程序根据上次访问时间删除旧的依赖项。
它不会删除“旧版本”,但由于您实际上可能有两个不同的活动项目具有两个不同版本的依赖项,所以无论如何我都不会这样做。相反,就像弗洛里安的回答一样,它删除了最近没有访问过的依赖项。
如果您想尝试一下,您可以:
- 访问GitHub 存储库
- 克隆存储库,或下载源代码
- 可选择检查代码以确保它不是恶意的
- 跑
bin/mvnclean
有一些选项可以覆盖默认的 Maven 存储库、忽略文件、设置阈值日期,但您可以在 GitHub 上的 README 中阅读这些选项。
在我完成更多工作之后,我可能会在某个时候将它打包为 Ruby gem,gem install mvnclean; mvnclean
如果您已经安装并运行了 Ruby,这将简化事情 ()。
您需要复制项目所需的依赖项。有了这些,请清除项目中 POM.XML 文件中<dependency>
嵌入到标签中的所有标签。<dependencies>
保存文件后,您将看不到Maven 依赖项Libraries
。然后请粘贴<dependency>
您之前复制的内容。
Maven会自动下载所需的jar包,保存文件后在生成的Maven Dependencies中也可以看到。 Libraries
谢谢。