Ying Wang, Ming Wen, Yepang Liu, Yibo Wang, Zhenming Li, Chao Wang, Hai Yu, Shing-Chi Cheung, Chang Xu, and Zhiliang Zhu. 2020. Watchman: monitoring dependency conflicts for Python library ecosystem. In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering (ICSE '20). 125-135.
BibTeX格式:
@inproceedings{wang2020watchman,
title={Watchman: Monitoring dependency conflicts for python library ecosystem},
author={Wang, Ying and Wen, Ming and Liu, Yepang and Wang, Yibo and Li, Zhenming and Wang, Chao and Yu, Hai and Cheung, Shing-Chi and Xu, Chang and Zhu, Zhiliang},
booktitle={Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering},
pages={125--135},
year={2020}
}
项目介绍
Watchman是一个持续监测PyPI生态软件库版本更新,并对python项目进行依赖冲突问题检测的技术框架。
它的主要功能有:(1)监测PyPI生态中依赖包的更新情况; (2)对启智、GitLink等开源社区Python项目进行周期性冲突问题检测;
(3)自动化提交依赖冲突问题报告; (4)生成Python项目的完整依赖图;
(5)为用户提供个人项目的依赖冲突检测;(6)提供在线检测服务 (http://www.watchman-pypi.com/)
背景
在使用PyPI中央存储库的软件包时,开发者需要在setup.py、requirement.txt和METADATA脚本中配置所需的版本约束。当软件库被其他项目重用时,此软件库及间接依赖将在项目构建时自动被安装。自动化构建将PyPI中央存储库和客户端库安装程序巧妙地结合起来,以管理依赖包的依赖关系。它大大简化了Python项目的构建过程。然而,这种自动化带来了潜在依赖冲突问题的风险,当安装的依赖包版本违反项目的某些版本约束时,可能会导致构建失败。
在Python的世界中,诊断依赖冲突问题是一项具有挑战性的任务。首先,第三方软件库的版本可能会随着时间的推移而变化。对于每个依赖的软件库,pip将安装满足相关约束的最新版本。因此,PyPI生态中软件库的任何版本更新都可能会影响下游软件项目所安装的第三方库的版本,使得其依赖树的拓扑结构发生变化,从而导致潜在的构建失败。其次,因为这种影响可以大范围地传递到下游项目,这可能会对Python生态产生广泛的冲击。手动识别受影响的下游项目对开发商来说是不切实际的。第三,在不实际安装Python项目的情况下,难以获得具有版本约束的完全依赖关系图。最先进的工具(如pipenv和poethy)只显示安装了哪些依赖包,在依赖冲突的场景下,无法解析软件项目完整的第三方库依赖全景图,因此,它们无法被用来实时监测软件生态的依赖冲突问题。为了应对上述挑战,我们开发了Watchman来实时监控Python生态中软件库的版本更新,及时帮助Python开发人员诊断、报告并修复依赖冲突问题。
依赖问题类型
Watchman对依赖冲突问题进行检测、预测并生成修复建议,主要分为以下两种类型:
Pattern A : 由PyPI中央仓库中的软件库更新引发的冲突。如果软件库更新后的版本,依然可以被安装进Python项目中,但却违反了项目依赖树中对它的版本约束,则将发生构建失败。
在该场景下我们将直接依赖项和传递依赖项之间的冲突称为Pattern A.a问题;传递依赖之间的冲突称之为Pattern A.b 问题。
Pattern B: 潜在的依赖冲突预测。如果Python项目对其第三方库采用开放式的版本范围约束,且软件库当前更新的最新版本已经接近其版本约束的上限,则后续的版本演化便很容易导致依赖冲突问题。
后续将陆续扩展其他的依赖问题检测。
安装
克隆项目
您可以通过git使用以下命令克隆项目到本地:
http_url:
git clone https://git.openi.org.cn/watchman/Watchman-tool.git
ssh_url:
git clone git@git.openi.org.cn:watchman/Watchman-tool.git
环境配置
操作系统:Windows 10、UBUNTU
相关依赖:
数据库:MySQL数据库,开发者可以通过导入sql目录下的.sql文件建立数据库表结构。
浏览器:Chrome(102.0.5005.115)64位浏览器。
快速使用说明
检测架构
Watchman可以持续监测PyPI生态中第三方库的更新情况,并利用其依赖元数据进行对启智生态中的Python项目中的依赖冲突问题进行诊断、报告与修复,其技术架构如下:
首先,Watchman会收集PyPI中所有软件库的元数据,其中包括每个第三方依赖的版本以及其依赖关系(直接依赖名称、版本约束等),此过程持续进行,依赖元数据库会不断进行自动化更新。在依赖数据收集完成的基础上,Watchman可以为任意一个待分析的Python软件项目解析出完全依赖图,通过分析依赖图中第三方依赖的实际安装版本与版本约束之间的关系完成依赖冲突问题的诊断。
Watchman进行问题检测的两个关键过程是PyPI依赖网络的构建和利用依赖信息检测问题,为了便于理解,接下来的说明中我们假设项目克隆到本地的
D:\
文件夹下。获取PyPI依赖网络
1. 首先在
D:\Watchman-tool\Watchman_PyPI_DA\run.py
中配置项目的下载和解压缩路径,项目中的默认路径如下:2. 在
D:\Watchman-tool\Watchman_PyPI_DA\utils\database_utils_pool.py
中配置数据库连接参数3. 通过执行以下命令完成PyPI生态依赖网络的获取:
python D:\Watchman-tool\Watchman_PyPI_DA\run.py
4. 由于依赖网络数据更新需要每天对整个PyPI生态系统进行全面分析,尤其是在初次构建时,这很耗时,实际执行时间可能取决于网络通信的质量。
检测Python项目依赖冲突问题
1. 首先在
D:\Watchman-tool\Watchman_Issue_Detector\openi.py (gitlink.py、gitee.py)
中配置待检测项目的下载和解压缩路径,以openi.py
为例,项目中的默认路径配置如下:2. 在
D:\Watchman-tool\Watchman_Issue_Detector\utils\database_utils_pool.py
中配置数据库连接参数3. 通过执行以下命令完成对应开源社区的依赖冲突问题的自动化检测和提交:
python D:\Watchman-tool\Watchman_Issue_Detector\openi.py
python D:\Watchman-tool\WWatchman_Issue_Detector\gitlink.py
python D:\Watchman-tool\Watchman_Issue_Detector\gitee.py
4. 生成的问题报告和修复意见信息如下:
在线检测服务
Watchman提供两种在线依赖冲突问题诊断服务:1. 点击链接进入Watchman在线检测服务,详情参见使用文档请见此处;2. GitHub Marketplace的Bot应用,可供开发者免费下载订阅 - [watchman-pypi](watchman-pypi · GitHub Marketplace),点击此处安装。
推荐的浏览器
推荐使用Chrome浏览器(79.0.3945.130及以上版本)。
使用指南
功能演示视频:
视频链接。
Python项目示例
为了便于说明,使用三个存在(潜在的)依赖冲突问题的Python项目进行演示,如下所示:
moto
1.3.14
ldapdomaindump
0.9.1
bcdata
0.3.5
Watchman的输入
Watchman支持两种类型的输入来诊断他们的依赖冲突问题:1)待分析的Python项目在PyPI上发布的名称和版本号;2)待分析的Python项目的依赖配置文件(即requirement.txt)。 例如,点击在 "DIAGNOSIS" 页面的 "Pagage Name/Version“按钮; 然后,您可以输入待分析的项目名称和版本号。
如果待分析的Python项目未在PyPI上发布,那么可以按”Import File“按钮,然后上传它的requirement.txt文件。
展示完整的依赖关系图
当用户在"DIAGNOSIS"页面输入了待检测的PyPI第三方库的名称及版本号或者上传了依赖配置文件(例如requirement.txt),点击 "Graph"按钮, Watchman会提供所分析项目的完整依赖关系图(FDG),FDG模拟安装所需依赖项的过程。点击 "Save"按钮,用户还可以将生成的FDG保存在图像或文本文件中,以供进一步分析。除此之外,它所有的下游项目也可以在这个页面上列出。
诊断依赖冲突问题
当用户在"DIAGNOSIS"页面点击"Start"按钮时, Watchman将会帮助诊断待分析项目的依赖冲突问题,并且提供详细的问题原因的修复方案信息。
PyPI生态系统拓扑结构概览
当点击"Go"按钮,用户可以看到PyPI生态系统拓扑结构的全貌,并且可以查看任何Python项目的详细依赖信息。
关键API说明
概述
Watchman是在收集PyPI中第三方库依赖元数据的基础上进行依赖冲突问题的检测,在具体进行实现时,我们将这两个过程的分别进行实现。其中,Watchman_PyPI_DA目录下存放的是PyPI依赖网络数据获取的代码,而Watchman_Issue_Detector目录下存放的则是项目依赖冲突问题检测的代码。
Watchman_PyPI_DA模块
模块图
Watchman_PyPI_DA目录下是整个生成PyPI依赖网络的功能模块,其中包含crawl_all_version、dependency_analyzer、dependency_finder三个主要的功能模块,以下为主要功能模块和相应关键API的介绍:
1. crawl_all_version模块
该模块中包含爬取依赖包信息的相关API。
1.1 crawl_all_file_name()
功能
爬取PyPI中所有依赖包的文件名,更新数据库。
参数
无。
返回值
无。
1.2 crawl_file_from_version()
功能
根据数据库中依赖包文件名下载依赖包至配置好的路径中,解压缩后删除非依赖配置文件。
参数
无。
返回值
无。
2. dependency_analyzer模块
该模块下包含对项目进行依赖分析的API。
2.1 analysis(file_path)
功能
对指定路径下项目文件进行处理,保留依赖配置文件并移动到存储项目的根路径下,分析目录下各项目的依赖。
参数
file_path:字符串类型,项目解压后文件的上一级路径。
例:D:\Watchman-tool\WatchmanSpiderData\watchman-spider-file-2022-6-21\pypi-uncompress-file\uncompress0。
返回值
无。
3. dependency_finder模块
该模块包含从依赖文件中获取直接依赖信息的API。
3.1 find_requirements(path)
功能
对路径下的依赖文件(METADATA、setup.py、requirements.txt)进行分析,获取依赖信息。
参数
path:字符串类型,依赖文件所在的上一级地址。
例:D:\Watchman-tool\WatchmanSpiderData\watchman-spider-file-2022-6-21\pypi-uncompress-file\uncompress0\flask- 2.1.2。
返回值
列表(List)类型数据,存放requirement.py中定义的DetectedRequirement类型数据,该类型具有以下属性:
name:字符串类型,PyPI包名,可为空。
version_specs:字符串类型,依赖限制,可为空。
requirement:字符串类型,完整的依赖描述,内容为name+version_specs,可为空。
url:字符串类型,项目下载地址,可为空。
3.2 from_requirements_metadata(metadatafile)
功能
对METADATA类型依赖文件进行分析,获取依赖信息。
参数
path:字符串类型,METADATA文件所在地址。
例:D:\Watchman-tool\WatchmanSpiderData\watchman-spider-file-2022-6-21\pypi-uncompress-file\uncompress0\flask- 2.1.2\METADATA。
返回值
列表(List)类型数据,存放requirement.py中定义的DetectedRequirement类型数据,该类型具有以下属性:
name:字符串类型,PyPI包名,可为空。
version_specs:字符串类型,依赖限制,可为空。
requirement:字符串类型,完整的依赖描述,内容为name+version_specs,可为空。
url:字符串类型,项目下载地址,可为空。
3.3 from_setup_py(setup_file)
功能
对setup.py类型依赖文件进行分析,获取依赖信息。
参数
path:字符串类型,setup.py文件所在地址。
例:D:\Watchman-tool\WatchmanSpiderData\watchman-spider-file-2022-6-21\pypi-uncompress-file\uncompress0\flask- 2.1.2\setup.py。
返回值
列表(List)类型数据,存放requirement.py中定义的DetectedRequirement类型数据,该类型具有以下属性:
name:字符串类型,PyPI包名,可为空。
version_specs:字符串类型,依赖限制,可为空。
requirement:字符串类型,完整的依赖描述,内容为name+version_specs,可为空。
url:字符串类型,项目下载地址,可为空。
3.4 from_requirements_txt(requirements_file)
功能
对requirements.txt类型依赖文件进行分析,获取依赖信息。
参数
path:字符串类型,requirements.txt文件所在地址。
例:D:\Watchman-tool\WatchmanSpiderData\watchman-spider-file-2022-6-21\pypi-uncompress-file\uncompress0\flask- 2.1.2\METADATA。
返回值
列表(List)类型数据,存放requirement.py中定义的DetectedRequirement类型数据,该类型具有以下属性:
name:字符串类型,PyPI包名,可为空。
version_specs:字符串类型,依赖限制,可为空。
requirement:字符串类型,完整的依赖描述,内容为name+version_specs,可为空。
url:字符串类型,项目下载地址,可为空。
Watchman_Issue_Detector模块
模块图
Watchman_Issue_Detector目录下是对开源社区中Python项目进行获取和检测的模块,其中包含clone_project、dependency_finder、conflict_detector、submit_issue四个主要的功能模块,以下为主要功能模块和相应关键API的介绍:
1. clone_project模块
该模块包含对开源社区中项目进行信息获取和克隆的API。
1.1 crawl_page(n, src)
功能
爬取开源社区中Python项目的信息,项目按更新时间排序。
参数
n:整型,表示想要爬取页面的页码。 src:字符串类型,表示项目所在的社区,目前支持gitee、gitlink、openi。
返回值
pro:元组列表(List),存放当前页面的项目信息,[{repo、owner、update_time、http_url、ssh_url、src},…],具体包括以下元素:
repo:字符串类型,项目的唯一标识。
owner:字符串类型,用户仓库的唯一标识。
update_time:字符串类型,项目的更新时间。
http_url:字符串类型。
ssh_url:字符串类型。
src:字符串类型,表示项目所在的社区,目前支持gitee、gitlink、openi。
1.2 clone(pro)
功能
克隆项目到本地。
参数
pro:元组列表(List),存放当前页面的项目信息,[{repo、owner、update_time、http_url、ssh_url、src},…],具体包括以下元素:
repo:字符串类型,项目的唯一标识。
owner:字符串类型,用户仓库的唯一标识。
update_time:字符串类型,项目的更新时间。
http_url:字符串类型。
ssh_url:字符串类型。
src:字符串类型,表示项目所在的社区,目前支持gitee、gitlink、openi。
返回值
check_pro:元组列表(List),存放在数据库中已有其直接依赖信息的项目信息,[{repo、owner、update_time、http_url、ssh_url、src},…],具体包括以下元素:
repo:字符串类型,项目的唯一标识。
owner:字符串类型,用户仓库的唯一标识。
update_time:字符串类型,项目的更新时间。
http_url:字符串类型。
ssh_url:字符串类型。
src:字符串类型,表示项目所在的社区,目前支持gitee、gitlink、openi。
2. conflict_detector模块
该模块包含了检测依赖冲突问题的API
2.1 detect_project_conflict(file_path, detect_requirements, src)
功能
检测项目的依赖结构是否存在冲突,并进行issue报告的生成。
参数
file_path:字符串类型,待检测项目地址。
例:D:\Watchman-tool\projectdata\2022-06-21\openi\files1\arspi@test@2022-06-21。
detect_requirements:列表类型,存放requirement.py中定义的DetectedRequirement类型数据,该类型具有以下属性:
name:字符串类型,PyPI包名。
version_specs:字符串类型,依赖限制。
requirement:字符串类型,完整的依赖描述,内容为name+version_specs。
url:字符串类型,项目下载地址,可为空。
src:字符串类型,表示项目所在的社区,目前支持gitee、gitlink、openi。
返回值
字符串类型数据,当检测到冲突时为issue内容,未检测到时为“no conflict ”。
3. submit_issue模块
该模块包含了提交issue的API。
3.1 submit(owner, pro_name, update_time, issue, src)
功能
提交检测到的issue报告。
参数
pro_name:字符串类型,项目的唯一标识。
owner:字符串类型,用户仓库的唯一标识。
update_time:字符串类型,项目的更新时间。
issue:字符串类型,所要提交的issue内容,格式为title +‘;## Issue description\n’+content。
src:字符串类型,表示项目所在的社区,目前支持gitee、gitlink、openi。
返回值
boolean类型, True:提交成功,False:提交失败。
开发者
以下人员是 Watchman工具代码的开发和维护核心贡献者:
张霆伟 (东北大学);孔玮 (东北大学);孙鹏 (东北大学);王一博 (东北大学);李朕名 (东北大学,微软);王超 (东北大学,厦门大学);
开源项目的通讯作者与负责团队:
王莹 wangying@swc.neu.edu.cn (东北大学 软件学院 智能软件开发技术研究所)
学术论文
我们开源了Watchman的源代码,如果您在科学出版物中使用 Watchman的相关代码,希望您通过以下文章来深入了解该工具的诞生:
文本格式:
BibTeX格式:
License
本项目采用
开源授权许可证,完整的授权说明已放置在License文件中。