compare.sh
· 718 B · Bash
Raw
#!/usr/bin/env bash
#
# compare_packages.sh
#
# Compare package lists from two systems:
# anduinos-packages.txt
# ubuntu-24-packages.txt
# Ensure both files exist
if [[ ! -f "anduinos-packages.txt" || ! -f "ubuntu-24-packages.txt" ]]; then
echo "Error: One or both package list files are missing."
echo "Please make sure anduinos-packages.txt and ubuntu-24-packages.txt are present."
exit 1
fi
echo "===== Packages installed on anduinos but NOT on ubuntu ====="
comm -23 <(sort anduinos-packages.txt) <(sort ubuntu-24-packages.txt)
echo
echo "===== Packages installed on ubuntu but NOT on anduinos ====="
comm -13 <(sort anduinos-packages.txt) <(sort ubuntu-24-packages.txt)
echo
echo "Comparison done."
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 |
10 | if [[ ! -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 |
14 | fi |
15 | |
16 | echo "===== Packages installed on anduinos but NOT on ubuntu =====" |
17 | comm -23 <(sort anduinos-packages.txt) <(sort ubuntu-24-packages.txt) |
18 | |
19 | echo |
20 | echo "===== Packages installed on ubuntu but NOT on anduinos =====" |
21 | comm -13 <(sort anduinos-packages.txt) <(sort ubuntu-24-packages.txt) |
22 | |
23 | echo |
24 | echo "Comparison done." |
25 |
1 | dpkg-query -f '${binary:Package}\n' -W > anduinos-packages.txt |
2 | dpkg-query -f '${binary:Package}\n' -W > ubuntu-24-packages.txt |
visualize.py
· 3.0 KiB · Python
Raw
import subprocess
from collections import defaultdict
def list_installed_packages():
"""获取所有已安装的包列表。"""
result = subprocess.run(
["dpkg-query", "-f", "${binary:Package}\n", "-W"],
stdout=subprocess.PIPE,
text=True
)
return result.stdout.strip().split("\n")
def get_package_dependencies(package):
"""查询单个包的直接依赖项。"""
result = subprocess.run(
["apt-cache", "depends", package],
stdout=subprocess.PIPE,
text=True
)
dependencies = []
for line in result.stdout.strip().split("\n"):
if line.strip().startswith("Depends:"):
dep = line.split(":", 1)[1].strip()
dep = dep.split(":")[0] # 去掉冒号后的部分
dependencies.append(dep)
return dependencies
def build_dependency_graph(packages):
"""构建包的依赖关系图。"""
totalPackages = len(packages)
processedPackages = 0
graph = defaultdict(list)
for package in packages:
dependencies = get_package_dependencies(package)
for dep in dependencies:
print(f"{package} -> {dep}")
graph[package].append(dep)
processedPackages += 1
print(f"已处理 {processedPackages}/{totalPackages} 个包")
return graph
def remove_redundant_edges(graph):
"""去除冗余的边。"""
def dfs(node, visited):
if node in visited:
return visited[node]
visited[node] = set()
for neighbor in graph[node]:
visited[node].update(dfs(neighbor, visited))
visited[node].add(node)
return visited[node]
# 创建 graph 的静态副本来避免动态修改引发问题
nodes = list(graph.keys())
reachable = {}
for node in nodes: # 这里使用静态副本
dfs(node, reachable)
minimal_graph = defaultdict(list)
for node in nodes: # 再次使用静态副本
direct_deps = set(graph[node])
for dep in graph[node]:
direct_deps -= reachable[dep]
minimal_graph[node] = list(direct_deps)
return minimal_graph
def generate_mermaid_graph(graph):
"""生成 Mermaid 图表的语法。"""
lines = ["stateDiagram-v2"]
for package, dependencies in graph.items():
for dep in dependencies:
lines.append(f" {package} --> {dep}")
return "\n".join(lines)
def main():
print("正在获取已安装的包...")
packages = list_installed_packages()
print("正在构建依赖图...")
graph = build_dependency_graph(packages)
print("正在去除冗余边...")
minimal_graph = remove_redundant_edges(graph)
print("正在生成 Mermaid 图表语法...")
mermaid_graph = generate_mermaid_graph(minimal_graph)
with open("dependency_graph.mmd", "w") as file:
file.write("---\n")
file.write("title: APT Dependency Graph\n")
file.write("---\n\n")
file.write(mermaid_graph)
print("Mermaid 图表已生成并保存为 dependency_graph.mmd")
if __name__ == "__main__":
main()
1 | import subprocess |
2 | from collections import defaultdict |
3 | |
4 | def 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 | |
13 | def 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 | |
28 | def 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 | |
42 | def 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 | |
67 | def 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 | |
75 | def 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 | |
96 | if __name__ == "__main__": |
97 | main() |
98 |