compare.sh
                        
                             · 718 B · Bash
                        
                    
                    
                      
                        原始文件
                      
                    
                      
                    
                        
                          
                        
                    
                    
                
                
                
            #!/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
                        
                             · 5.6 KiB · Python
                        
                    
                    
                      
                        原始文件
                      
                    
                      
                    
                        
                          
                        
                    
                    
                
                
                
            #!/usr/bin/env python3
import subprocess
from collections import defaultdict, deque
from concurrent.futures import ThreadPoolExecutor
import threading
import os
import sys
def list_installed_packages():
    """Retrieve a list of all 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):
    """Query the direct dependencies of a single 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]  # Remove parts after colon
            dependencies.append(dep)
    return dependencies
def build_dependency_graph(packages):
    """Build a dependency graph for the packages and save it to a file."""
    graph = defaultdict(list)
    lock = threading.Lock()
    
    def process_package(package):
        dependencies = get_package_dependencies(package)
        with lock:
            graph[package].extend(dependencies)
    total_packages = len(packages)
    with ThreadPoolExecutor(max_workers=20) as executor:
        for i, _ in enumerate(executor.map(process_package, packages), start=1):
            progress = (i / total_packages) * 100
            print(f"Building dependency graph... {progress:.2f}% completed", end="\r")
    output_path = "/tmp/pkg.txt"
    with open(output_path, "w") as f:
        for package, dependencies in graph.items():
            for dep in dependencies:
                f.write(f"{package}-->{dep}\n")
    print(f"\nDependency graph built and saved to {output_path}")
def load_dependency_graph(file_path="/tmp/pkg.txt"):
    """Load the dependency graph from a file."""
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"File {file_path} does not exist. Please run the build mode first.")
    graph = defaultdict(list)
    reverse_graph = defaultdict(list)
    with open(file_path, "r") as f:
        for line in f:
            line = line.strip()
            if "-->" in line:
                source, target = line.split("-->")
                graph[source].append(target)
                reverse_graph[target].append(source)
    return graph, reverse_graph
def trim_package_name(package):
    """Trim package name to conform to Mermaid syntax."""
    return package.replace("-", "_").replace(".", "_").replace("+", "_").replace(":", "_").replace("<", "_").replace(">", "_")
def generate_mermaid_graph(graph, root_package, exclude_leaves=False):
    """Generate a Mermaid diagram syntax for the graph."""
    lines = ["stateDiagram-v2"]
    visited = set()
    queue = deque([root_package])
    is_leaf = lambda pkg: len(graph.get(pkg, [])) == 0  # Determine if it is a leaf node
    while queue:
        package = queue.popleft()
        if package in visited:
            continue
        visited.add(package)
        dependencies = graph.get(package, [])
        for dep in dependencies:
            if exclude_leaves and is_leaf(dep):
                continue  # Skip leaf nodes
            lines.append(f"    {trim_package_name(package)} --> {trim_package_name(dep)}")
            if dep not in visited:
                queue.append(dep)
    return "\n".join(lines)
def build_mode():
    print("Retrieving installed packages...")
    packages = list_installed_packages()
    print("Building dependency graph...")
    build_dependency_graph(packages)
def depends_mode(package, exclude_leaves):
    graph, _ = load_dependency_graph()
    if package not in graph:
        print(f"Package {package} is not in the dependency graph.")
        return
    print("Generating dependency graph...")
    mermaid_graph = generate_mermaid_graph(graph, package, exclude_leaves)
    with open(f"{package}_depends.mmd", "w") as f:
        f.write("---\n")
        f.write(f"title: {package} Dependency Graph\n")
        f.write("---\n\n")
        f.write(mermaid_graph)
    print(f"Dependency graph generated and saved as {package}_depends.mmd")
def rdepends_mode(package, exclude_leaves):
    _, reverse_graph = load_dependency_graph()
    if package not in reverse_graph:
        print(f"Package {package} is not in the reverse dependency graph.")
        return
    print("Generating reverse dependency graph...")
    mermaid_graph = generate_mermaid_graph(reverse_graph, package, exclude_leaves)
    with open(f"{package}_rdepends.mmd", "w") as f:
        f.write("---\n")
        f.write(f"title: {package} Reverse Dependency Graph\n")
        f.write("---\n\n")
        f.write(mermaid_graph)
    print(f"Reverse dependency graph generated and saved as {package}_rdepends.mmd")
def main():
    if len(sys.argv) < 2:
        print("Usage: ./vispkg.py [build|depends|rdepends] [package] [--no-leaves]")
        sys.exit(1)
    mode = sys.argv[1]
    exclude_leaves = "--no-leaves" in sys.argv
    if mode == "build":
        build_mode()
    elif mode == "depends":
        if len(sys.argv) < 3:
            print("Usage: ./vispkg.py depends <package> [--no-leaves]")
            sys.exit(1)
        depends_mode(sys.argv[2], exclude_leaves)
    elif mode == "rdepends":
        if len(sys.argv) < 3:
            print("Usage: ./vispkg.py rdepends <package> [--no-leaves]")
            sys.exit(1)
        rdepends_mode(sys.argv[2], exclude_leaves)
    else:
        print("Unknown mode. Please use: build, depends, or rdepends.")
        sys.exit(1)
if __name__ == "__main__":
    main()
                | 1 | #!/usr/bin/env python3 | 
| 2 | import subprocess | 
| 3 | from collections import defaultdict, deque | 
| 4 | from concurrent.futures import ThreadPoolExecutor | 
| 5 | import threading | 
| 6 | import os | 
| 7 | import sys | 
| 8 | |
| 9 | def list_installed_packages(): | 
| 10 | """Retrieve a list of all installed packages.""" | 
| 11 | result = subprocess.run( | 
| 12 | ["dpkg-query", "-f", "${binary:Package}\n", "-W"], | 
| 13 | stdout=subprocess.PIPE, | 
| 14 | text=True | 
| 15 | ) | 
| 16 | return result.stdout.strip().split("\n") | 
| 17 | |
| 18 | def get_package_dependencies(package): | 
| 19 | """Query the direct dependencies of a single package.""" | 
| 20 | result = subprocess.run( | 
| 21 | ["apt-cache", "depends", package], | 
| 22 | stdout=subprocess.PIPE, | 
| 23 | text=True | 
| 24 | ) | 
| 25 | dependencies = [] | 
| 26 | for line in result.stdout.strip().split("\n"): | 
| 27 | if line.strip().startswith("Depends:"): | 
| 28 | dep = line.split(":", 1)[1].strip() | 
| 29 | dep = dep.split(":")[0] # Remove parts after colon | 
| 30 | dependencies.append(dep) | 
| 31 | return dependencies | 
| 32 | |
| 33 | def build_dependency_graph(packages): | 
| 34 | """Build a dependency graph for the packages and save it to a file.""" | 
| 35 | graph = defaultdict(list) | 
| 36 | lock = threading.Lock() | 
| 37 | |
| 38 | def process_package(package): | 
| 39 | dependencies = get_package_dependencies(package) | 
| 40 | with lock: | 
| 41 | graph[package].extend(dependencies) | 
| 42 | |
| 43 | total_packages = len(packages) | 
| 44 | with ThreadPoolExecutor(max_workers=20) as executor: | 
| 45 | for i, _ in enumerate(executor.map(process_package, packages), start=1): | 
| 46 | progress = (i / total_packages) * 100 | 
| 47 | print(f"Building dependency graph... {progress:.2f}% completed", end="\r") | 
| 48 | |
| 49 | output_path = "/tmp/pkg.txt" | 
| 50 | with open(output_path, "w") as f: | 
| 51 | for package, dependencies in graph.items(): | 
| 52 | for dep in dependencies: | 
| 53 | f.write(f"{package}-->{dep}\n") | 
| 54 | |
| 55 | print(f"\nDependency graph built and saved to {output_path}") | 
| 56 | |
| 57 | def load_dependency_graph(file_path="/tmp/pkg.txt"): | 
| 58 | """Load the dependency graph from a file.""" | 
| 59 | if not os.path.exists(file_path): | 
| 60 | raise FileNotFoundError(f"File {file_path} does not exist. Please run the build mode first.") | 
| 61 | |
| 62 | graph = defaultdict(list) | 
| 63 | reverse_graph = defaultdict(list) | 
| 64 | |
| 65 | with open(file_path, "r") as f: | 
| 66 | for line in f: | 
| 67 | line = line.strip() | 
| 68 | if "-->" in line: | 
| 69 | source, target = line.split("-->") | 
| 70 | graph[source].append(target) | 
| 71 | reverse_graph[target].append(source) | 
| 72 | |
| 73 | return graph, reverse_graph | 
| 74 | |
| 75 | def trim_package_name(package): | 
| 76 | """Trim package name to conform to Mermaid syntax.""" | 
| 77 | return package.replace("-", "_").replace(".", "_").replace("+", "_").replace(":", "_").replace("<", "_").replace(">", "_") | 
| 78 | |
| 79 | def generate_mermaid_graph(graph, root_package, exclude_leaves=False): | 
| 80 | """Generate a Mermaid diagram syntax for the graph.""" | 
| 81 | lines = ["stateDiagram-v2"] | 
| 82 | visited = set() | 
| 83 | queue = deque([root_package]) | 
| 84 | is_leaf = lambda pkg: len(graph.get(pkg, [])) == 0 # Determine if it is a leaf node | 
| 85 | |
| 86 | while queue: | 
| 87 | package = queue.popleft() | 
| 88 | if package in visited: | 
| 89 | continue | 
| 90 | visited.add(package) | 
| 91 | |
| 92 | dependencies = graph.get(package, []) | 
| 93 | for dep in dependencies: | 
| 94 | if exclude_leaves and is_leaf(dep): | 
| 95 | continue # Skip leaf nodes | 
| 96 | |
| 97 | lines.append(f" {trim_package_name(package)} --> {trim_package_name(dep)}") | 
| 98 | if dep not in visited: | 
| 99 | queue.append(dep) | 
| 100 | |
| 101 | return "\n".join(lines) | 
| 102 | |
| 103 | def build_mode(): | 
| 104 | print("Retrieving installed packages...") | 
| 105 | packages = list_installed_packages() | 
| 106 | print("Building dependency graph...") | 
| 107 | build_dependency_graph(packages) | 
| 108 | |
| 109 | def depends_mode(package, exclude_leaves): | 
| 110 | graph, _ = load_dependency_graph() | 
| 111 | if package not in graph: | 
| 112 | print(f"Package {package} is not in the dependency graph.") | 
| 113 | return | 
| 114 | |
| 115 | print("Generating dependency graph...") | 
| 116 | mermaid_graph = generate_mermaid_graph(graph, package, exclude_leaves) | 
| 117 | |
| 118 | with open(f"{package}_depends.mmd", "w") as f: | 
| 119 | f.write("---\n") | 
| 120 | f.write(f"title: {package} Dependency Graph\n") | 
| 121 | f.write("---\n\n") | 
| 122 | f.write(mermaid_graph) | 
| 123 | |
| 124 | print(f"Dependency graph generated and saved as {package}_depends.mmd") | 
| 125 | |
| 126 | def rdepends_mode(package, exclude_leaves): | 
| 127 | _, reverse_graph = load_dependency_graph() | 
| 128 | if package not in reverse_graph: | 
| 129 | print(f"Package {package} is not in the reverse dependency graph.") | 
| 130 | return | 
| 131 | |
| 132 | print("Generating reverse dependency graph...") | 
| 133 | mermaid_graph = generate_mermaid_graph(reverse_graph, package, exclude_leaves) | 
| 134 | |
| 135 | with open(f"{package}_rdepends.mmd", "w") as f: | 
| 136 | f.write("---\n") | 
| 137 | f.write(f"title: {package} Reverse Dependency Graph\n") | 
| 138 | f.write("---\n\n") | 
| 139 | f.write(mermaid_graph) | 
| 140 | |
| 141 | print(f"Reverse dependency graph generated and saved as {package}_rdepends.mmd") | 
| 142 | |
| 143 | def main(): | 
| 144 | if len(sys.argv) < 2: | 
| 145 | print("Usage: ./vispkg.py [build|depends|rdepends] [package] [--no-leaves]") | 
| 146 | sys.exit(1) | 
| 147 | |
| 148 | mode = sys.argv[1] | 
| 149 | exclude_leaves = "--no-leaves" in sys.argv | 
| 150 | |
| 151 | if mode == "build": | 
| 152 | build_mode() | 
| 153 | elif mode == "depends": | 
| 154 | if len(sys.argv) < 3: | 
| 155 | print("Usage: ./vispkg.py depends <package> [--no-leaves]") | 
| 156 | sys.exit(1) | 
| 157 | depends_mode(sys.argv[2], exclude_leaves) | 
| 158 | elif mode == "rdepends": | 
| 159 | if len(sys.argv) < 3: | 
| 160 | print("Usage: ./vispkg.py rdepends <package> [--no-leaves]") | 
| 161 | sys.exit(1) | 
| 162 | rdepends_mode(sys.argv[2], exclude_leaves) | 
| 163 | else: | 
| 164 | print("Unknown mode. Please use: build, depends, or rdepends.") | 
| 165 | sys.exit(1) | 
| 166 | |
| 167 | if __name__ == "__main__": | 
| 168 | main() | 
| 169 |