Hier ist ein Ruby-Skript, das mit rdepends überprüft, ob ein Paket eine Abhängigkeit für ein anderes installiertes Paket darstellt. Das sagt nicht genau, was Sie ausgewählt haben, aber das hängt nicht von Ihren Protokolldateien ab (die möglicherweise gedreht wurden).
Durch das Installieren von Paketen, die als Root-Pakete aufgeführt sind, werden alle in untergeordneten Paketen aufgeführten Pakete installiert. Sie sollten also fast (siehe Nachteile unten) dieselbe Paketliste haben.
Die untergeordnete Liste zeigt die Pakete an, die Abhängigkeiten von anderen untergeordneten Paketen oder Root-Paketen sind.
Dieser Ansatz weist einige Nachteile auf:
- Einige Pakete werden möglicherweise nicht als root aufgeführt, wenn sie Abhängigkeiten von einem optionalen, empfohlenen Paket sind, das Sie ausgewählt haben. Zum Beispiel auf meinem Server
apache2
bei Kindern Pakete aufgeführt ist , weil ich auch haben libapache2-mod-php
, libapache2-mpm-itk
und python-letsencrypt-apache
installiert , die haben apache2
als Abhängigkeit.
- Zyklische Abhängigkeiten (Pakete, die direkt oder indirekt voneinander abhängen) werden in untergeordneten Paketen aufgeführt (zum Beispiel:
libapache2-mod-php
und libapache2-mod-php7.0
). Es gibt einen Abschnitt, in dem der wahrscheinliche Zyklus aufgeführt ist (überprüfen Sie die Paket-Vorfahren für 5 Generationen). Sie sollten ihn einschließen, um dieselbe Liste von Paketen zu erhalten (es sei denn, ich habe etwas anderes übersehen).
#!/usr/bin/env ruby
class ListRootPackages
def run
count = manual_marked_packages.count
@dependencies ||= {}
@root_packages ||= begin
manual_marked_packages.each_with_index.map do |package, index|
STDERR.print " #{index + 1} / #{count} \r"
intersection = manual_marked_packages & reverse_dependencies(package)
if intersection.any?
@dependencies[package] = intersection
nil
else
package
end
end.compact
end
end
def potential_cyclic_dependences
run
@potential_cyclic_dependences ||= @dependencies.keys.map do |package|
package unless has_root_ancestor?(package, 5)
end.compact
end
def has_root_ancestor?(package, level=0)
return true if @root_packages.include?(package)
return false if level.zero?
@dependencies[package].any? { |parent| has_root_ancestor?(parent, level - 1) }
end
def root_packages
run
@root_packages
end
def dependencies
run
@dependencies
end
def manual_marked_packages
@manual_marked_packages ||= parse_cli_list(`apt-mark showmanual`)
end
private
def reverse_dependencies(package)
parse_cli_list(`apt-cache rdepends #{package}`)[2..-1]
end
def parse_cli_list(list)
list.split("\n").map(&:strip)
end
end
list = ListRootPackages.new
list.run
puts "===== Root Packages (#{list.root_packages.count}) ====="
puts list.root_packages.join("\n")
puts
puts "===== Children packages (#{list.dependencies.count}) ====="
puts list.dependencies.map { |package, parents| "#{package}: #{parents.join(', ')}" }.join("\n")
puts
puts "===== Potential cyclic dependencies (#{list.potential_cyclic_dependences.count}) ====="
puts list.potential_cyclic_dependences.join(", ")
Wenn jemand das in Bash oder Python konvertieren möchte, wäre das schön, da Ruby weniger häufig auf Servern installiert wird als Bash oder Python.