Last active 1735293001

Revision 5ca371570c4101b30d5f7a25b31a14968e99db4e

compare.sh Raw
1#!/usr/bin/env bash
2#
3# compare_packages.sh
4#
5# Compare package lists from two systems:
6# anduinos-packages.txt
7# ubuntu-24-packages.txt
8
9# Ensure both files exist
10if [[ ! -f "anduinos-packages.txt" || ! -f "ubuntu-24-packages.txt" ]]; then
11 echo "Error: One or both package list files are missing."
12 echo "Please make sure anduinos-packages.txt and ubuntu-24-packages.txt are present."
13 exit 1
14fi
15
16echo "===== Packages installed on anduinos but NOT on ubuntu ====="
17comm -23 <(sort anduinos-packages.txt) <(sort ubuntu-24-packages.txt)
18
19echo
20echo "===== Packages installed on ubuntu but NOT on anduinos ====="
21comm -13 <(sort anduinos-packages.txt) <(sort ubuntu-24-packages.txt)
22
23echo
24echo "Comparison done."
25
export.sh Raw
1dpkg-query -f '${binary:Package}\n' -W > anduinos-packages.txt
2dpkg-query -f '${binary:Package}\n' -W > ubuntu-24-packages.txt
visualize.py Raw
1import subprocess
2from collections import defaultdict
3
4def list_installed_packages():
5 """获取所有已安装的包列表。"""
6 result = subprocess.run(
7 ["dpkg-query", "-f", "${binary:Package}\n", "-W"],
8 stdout=subprocess.PIPE,
9 text=True
10 )
11 return result.stdout.strip().split("\n")
12
13def get_package_dependencies(package):
14 """查询单个包的直接依赖项。"""
15 result = subprocess.run(
16 ["apt-cache", "depends", package],
17 stdout=subprocess.PIPE,
18 text=True
19 )
20 dependencies = []
21 for line in result.stdout.strip().split("\n"):
22 if line.strip().startswith("Depends:"):
23 dep = line.split(":", 1)[1].strip()
24 dep = dep.split(":")[0] # 去掉冒号后的部分
25 dependencies.append(dep)
26 return dependencies
27
28def build_dependency_graph(packages):
29 """构建包的依赖关系图。"""
30 totalPackages = len(packages)
31 processedPackages = 0
32 graph = defaultdict(list)
33 for package in packages:
34 dependencies = get_package_dependencies(package)
35 for dep in dependencies:
36 print(f"{package} -> {dep}")
37 graph[package].append(dep)
38 processedPackages += 1
39 print(f"已处理 {processedPackages}/{totalPackages} 个包")
40 return graph
41
42def remove_redundant_edges(graph):
43 """去除冗余的边。"""
44 def dfs(node, visited):
45 if node in visited:
46 return visited[node]
47 visited[node] = set()
48 for neighbor in graph[node]:
49 visited[node].update(dfs(neighbor, visited))
50 visited[node].add(node)
51 return visited[node]
52
53 # 创建 graph 的静态副本来避免动态修改引发问题
54 nodes = list(graph.keys())
55 reachable = {}
56 for node in nodes: # 这里使用静态副本
57 dfs(node, reachable)
58
59 minimal_graph = defaultdict(list)
60 for node in nodes: # 再次使用静态副本
61 direct_deps = set(graph[node])
62 for dep in graph[node]:
63 direct_deps -= reachable[dep]
64 minimal_graph[node] = list(direct_deps)
65 return minimal_graph
66
67def generate_mermaid_graph(graph):
68 """生成 Mermaid 图表的语法。"""
69 lines = ["stateDiagram-v2"]
70 for package, dependencies in graph.items():
71 for dep in dependencies:
72 lines.append(f" {package} --> {dep}")
73 return "\n".join(lines)
74
75def main():
76 print("正在获取已安装的包...")
77 packages = list_installed_packages()
78
79 print("正在构建依赖图...")
80 graph = build_dependency_graph(packages)
81
82 print("正在去除冗余边...")
83 minimal_graph = remove_redundant_edges(graph)
84
85 print("正在生成 Mermaid 图表语法...")
86 mermaid_graph = generate_mermaid_graph(minimal_graph)
87
88 with open("dependency_graph.mmd", "w") as file:
89 file.write("---\n")
90 file.write("title: APT Dependency Graph\n")
91 file.write("---\n\n")
92 file.write(mermaid_graph)
93
94 print("Mermaid 图表已生成并保存为 dependency_graph.mmd")
95
96if __name__ == "__main__":
97 main()
98