Zuletzt aktiv 1735293001

compare.sh Orginalformat
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 Orginalformat
1dpkg-query -f '${binary:Package}\n' -W > anduinos-packages.txt
2dpkg-query -f '${binary:Package}\n' -W > ubuntu-24-packages.txt
visualize.py Orginalformat
1#!/usr/bin/env python3
2import subprocess
3from collections import defaultdict, deque
4from concurrent.futures import ThreadPoolExecutor
5import threading
6import os
7import sys
8import webbrowser
9import urllib.request
10
11MERMAID_TEMPLATE = """
12<!DOCTYPE html>
13<html>
14<head>
15 <meta charset="UTF-8">
16 <script src="mermaid.min.js"></script>
17 <script src="panzoom.min.js"></script>
18 <script>
19 document.addEventListener("DOMContentLoaded", () => {{
20 mermaid.initialize({{ startOnLoad: true }});
21
22 mermaid.contentLoaded().then(() => {{
23 const svg = document.querySelector(".mermaid > svg");
24 if (svg) {{
25 const panzoom = Panzoom(svg, {{ maxScale: 5, minScale: 0.5 }});
26 svg.parentElement.addEventListener('wheel', panzoom.zoomWithWheel);
27 }} else {{
28 console.error("Mermaid SVG not found for Panzoom initialization.");
29 }}
30 }});
31 }});
32 </script>
33 <style>
34 body {{
35 margin: 0;
36 overflow: hidden;
37 display: flex;
38 justify-content: center;
39 align-items: center;
40 height: 100vh;
41 background-color: #f4f4f4;
42 }}
43 #diagram-container {{
44 width: 100%;
45 height: 100%;
46 overflow: hidden;
47 position: relative;
48 }}
49 .mermaid {{
50 width: 100%;
51 height: 100%;
52 }}
53 </style>
54</head>
55<body>
56 <div id="diagram-container">
57 <div class="mermaid">
58{graph_content}
59 </div>
60 </div>
61</body>
62</html>
63"""
64
65
66def ensure_local_files():
67 """Ensure Mermaid.js and Panzoom.js are available locally."""
68 js_files = {
69 "mermaid.min.js": "https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js",
70 "panzoom.min.js": "https://cdn.jsdelivr.net/npm/panzoom@9.4.3/dist/panzoom.min.js",
71 }
72 tmp_dir = "/tmp"
73
74 for filename, url in js_files.items():
75 file_path = os.path.join(tmp_dir, filename)
76 if not os.path.exists(file_path):
77 print(f"Downloading {filename}...")
78 urllib.request.urlretrieve(url, file_path)
79
80def preview_mermaid_graph(file_path):
81 """Preview Mermaid graph in a browser."""
82 ensure_local_files()
83
84 if not os.path.exists(file_path):
85 print(f"File {file_path} does not exist.")
86 return
87
88 # Load the Mermaid graph content
89 with open(file_path, "r") as f:
90 graph_content = f.read()
91
92 # Prepare the HTML file content
93 html_content = MERMAID_TEMPLATE.format(graph_content=graph_content)
94
95 # Write the HTML to a temporary file
96 html_file_path = f"{file_path}.html"
97 with open(html_file_path, "w") as html_file:
98 html_file.write(html_content)
99
100 # Copy JS files to the same directory
101 for js_file in ["mermaid.min.js", "panzoom.min.js"]:
102 src = os.path.join("/tmp", js_file)
103 dst = os.path.join(os.path.dirname(html_file_path), js_file)
104 if not os.path.exists(dst):
105 subprocess.run(["cp", src, dst])
106
107 # Open the HTML file in the default web browser
108 print(f"Opening {html_file_path} in the browser...")
109 webbrowser.open(f"file://{os.path.abspath(html_file_path)}", new=2)
110
111def list_installed_packages():
112 """Retrieve a list of all installed packages."""
113 result = subprocess.run(
114 ["dpkg-query", "-f", "${binary:Package}\n", "-W"],
115 stdout=subprocess.PIPE,
116 text=True
117 )
118 return result.stdout.strip().split("\n")
119
120def get_package_dependencies(package):
121 """Query the direct dependencies of a single package."""
122 result = subprocess.run(
123 ["apt-cache", "depends", package],
124 stdout=subprocess.PIPE,
125 text=True
126 )
127 dependencies = []
128 for line in result.stdout.strip().split("\n"):
129 if line.strip().startswith("Depends:"):
130 dep = line.split(":", 1)[1].strip()
131 dep = dep.split(":")[0] # Remove parts after colon
132 dependencies.append(dep)
133 return dependencies
134
135def build_dependency_graph(packages):
136 """Build a dependency graph for the packages and save it to a file."""
137 graph = defaultdict(list)
138 lock = threading.Lock()
139
140 def process_package(package):
141 dependencies = get_package_dependencies(package)
142 with lock:
143 graph[package].extend(dependencies)
144
145 total_packages = len(packages)
146 with ThreadPoolExecutor(max_workers=20) as executor:
147 for i, _ in enumerate(executor.map(process_package, packages), start=1):
148 progress = (i / total_packages) * 100
149 print(f"Building dependency graph... {progress:.2f}% completed", end="\r")
150
151 output_path = "/tmp/pkg.txt"
152 with open(output_path, "w") as f:
153 for package, dependencies in graph.items():
154 for dep in dependencies:
155 f.write(f"{package}-->{dep}\n")
156
157 print(f"\nDependency graph built and saved to {output_path}")
158
159def load_dependency_graph(file_path="/tmp/pkg.txt"):
160 """Load the dependency graph from a file."""
161 if not os.path.exists(file_path):
162 raise FileNotFoundError(f"File {file_path} does not exist. Please run the build mode first.")
163
164 graph = defaultdict(list)
165 reverse_graph = defaultdict(list)
166
167 with open(file_path, "r") as f:
168 for line in f:
169 line = line.strip()
170 if "-->" in line:
171 source, target = line.split("-->")
172 graph[source].append(target)
173 reverse_graph[target].append(source)
174
175 return graph, reverse_graph
176
177def trim_package_name(package):
178 """Trim package name to conform to Mermaid syntax."""
179 return package.replace("-", "_").replace(".", "_").replace("+", "_").replace(":", "_").replace("<", "_").replace(">", "_")
180
181def generate_mermaid_graph(graph, root_package, exclude_leaves=False):
182 """Generate a Mermaid diagram syntax for the graph."""
183 lines = ["stateDiagram-v2"]
184 visited = set()
185 queue = deque([root_package])
186 is_leaf = lambda pkg: len(graph.get(pkg, [])) == 0 # Determine if it is a leaf node
187
188 while queue:
189 package = queue.popleft()
190 if package in visited:
191 continue
192 visited.add(package)
193
194 dependencies = graph.get(package, [])
195 for dep in dependencies:
196 if exclude_leaves and is_leaf(dep):
197 continue # Skip leaf nodes
198
199 lines.append(f" {trim_package_name(package)} --> {trim_package_name(dep)}")
200 if dep not in visited:
201 queue.append(dep)
202
203 return "\n".join(lines)
204
205def build_mode():
206 print("Retrieving installed packages...")
207 packages = list_installed_packages()
208 print("Building dependency graph...")
209 build_dependency_graph(packages)
210
211def depends_mode(package, exclude_leaves):
212 graph, _ = load_dependency_graph()
213 if package not in graph:
214 print(f"Package {package} is not in the dependency graph.")
215 return
216
217 print("Generating dependency graph...")
218 mermaid_graph = generate_mermaid_graph(graph, package, exclude_leaves)
219
220 output_file = f"{package}_depends.mmd"
221 with open(output_file, "w") as f:
222 f.write("---\n")
223 f.write(f"title: {package} Dependency Graph\n")
224 f.write("---\n\n")
225 f.write(mermaid_graph)
226
227 print(f"Dependency graph generated and saved as {output_file}")
228 preview_mermaid_graph(output_file)
229
230def rdepends_mode(package, exclude_leaves):
231 _, reverse_graph = load_dependency_graph()
232 if package not in reverse_graph:
233 print(f"Package {package} is not in the reverse dependency graph.")
234 return
235
236 print("Generating reverse dependency graph...")
237 mermaid_graph = generate_mermaid_graph(reverse_graph, package, exclude_leaves)
238
239 output_file = f"{package}_rdepends.mmd"
240 with open(output_file, "w") as f:
241 f.write("---\n")
242 f.write(f"title: {package} Reverse Dependency Graph\n")
243 f.write("---\n\n")
244 f.write(mermaid_graph)
245
246 print(f"Reverse dependency graph generated and saved as {output_file}")
247 preview_mermaid_graph(output_file)
248
249def main():
250 if len(sys.argv) < 2:
251 print("Usage: ./vispkg.py [build|depends|rdepends] [package] [--no-leaves]")
252 sys.exit(1)
253
254 mode = sys.argv[1]
255 exclude_leaves = "--no-leaves" in sys.argv
256
257 if mode == "build":
258 build_mode()
259 elif mode == "depends":
260 if len(sys.argv) < 3:
261 print("Usage: ./vispkg.py depends <package> [--no-leaves]")
262 sys.exit(1)
263 depends_mode(sys.argv[2], exclude_leaves)
264 elif mode == "rdepends":
265 if len(sys.argv) < 3:
266 print("Usage: ./vispkg.py rdepends <package> [--no-leaves]")
267 sys.exit(1)
268 rdepends_mode(sys.argv[2], exclude_leaves)
269 else:
270 print("Unknown mode. Please use: build, depends, or rdepends.")
271 sys.exit(1)
272
273if __name__ == "__main__":
274 main()
275