compare.sh
· 718 B · Bash
Eredeti
#!/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
Eredeti
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 |