Playing with RPM dependencies: pruning the tree

I've set up a Fedora 9 and stripped everything I don't need out of it. Now I would like to make a kickstart profile out of it. But instead of telling kickstart to install the (mandatory) basesystem and then removing all the packages I list, I want to tell it to not install ANYTHING, except the packages I tell it to (ie. the basesystem minus some crap).

So, I took the list of packages that I had installed, generated a dependency tree of it (using the graph generator from the previous post) and then threw out all packages in the list that were going to be installed anyway because the are dependencies of other packages.

This is the script I used:


$AllPackages = {};
$Requires = {};
$RequiredBy = {};

sub parseGeneratedDOTFile {
my ($filename) = @_;

open IN, "$filename";
while(my $line = <IN>) {
if($line =~ /^"([^"]+)" -> "([^"]+)";$/) {
$AllPackages->{$1} = 1;
$AllPackages->{$2} = 1;
$Requires->{$1}->{$2} = 1;
$RequiredBy->{$2}->{$1} = 1;
close IN;

# requires(a,b) -> does a require b ?
sub requires {
my ($a, $b) = @_;
return $Requires->{$a}->{$b};

# isRequiredBy(a,b) -> is a required by b ? (b requires a)
sub requires {
my ($a, $b) = @_;
return $RequiredBy->{$a}->{$b};

sub getAllDependenciesRecursively {
my (@list) = @_;

my $newlist = {};

foreach my $i (@list) {
$newlist->{$i} = 1;
foreach my $dep (keys %{$Requires->{$i}}) {
$newlist->{$dep} = 1;

my @output = keys %$newlist;

if(scalar(@output) > scalar(@list)) {
# something in the list changed, recurse more
return getAllDependenciesRecursively(@output);
} else {
return @output;

sub getMinimalSetToInstall {
my (@list) = @_;
my %bla = map { $_ => 1 } @list;
my $old = \%bla;
my $new = {};

foreach my $pkg (@list) {
my @revdeps = keys %{$RequiredBy->{$pkg}};
if(scalar(@revdeps) != 0) {
my $toBeAdded = 1;
# this package is required by some packages
# check if any of those packages is in the list we need to check
foreach my $d (@revdeps) {
if($old->{$d} == 1) {
$toBeAdded = 0;

if($toBeAdded == 1) {
$new->{$pkg} = 1;
} else {
# This package isn't required by anything else, so just keep it in the list
$new->{$pkg} = 1;

return keys %{$new}


@origlist = keys %{$AllPackages};
@smalllist = getMinimalSetToInstall(@origlist);
@generatedlist = getAllDependenciesRecursively((@smalllist));

if(scalar(@origlist) == scalar(@generatedlist)) {
print "Succesfully expanded minimal list into full list!\n\n";
print "Original list (".scalar(@origlist)." packages):\n";
print join " ", @origlist;
print "\n\n";
print "Condensed list (".scalar(@smalllist)." packages):\n";
print join " ", @smalllist;
print "\n";

This is the result so far (I haven't taken a detailed look at this output yet):

Succesfully expanded minimal list into full list!

Original list (196 packages):
glibc pciutils which iproute kudzu file rsyslog libattr libdhcp rpm less crontabs libsysfs nc sysvinit-tools dmraid hesiod checkpolicy system-config-firewall-tui findutils dbus-glib mkinitrd libidn tcpdump pth newt coreutils selinux-policy libpcap libselinux pygpgme grub libselinux-python time krb5-libs audit-libs newt-python pinentry kernel cyrus-sasl-plain gpgme anacron readline audit-libs-python iputils cracklib-dicts upstart hwdata man chkconfig initscripts gnupg2 glib2 procps file-libs gawk fedora-release-notes cyrus-sasl-lib psmisc nash mdadm libdhcp6client grep policycoreutils bash zlib bind-libs yum-metadata-parser setuptool ncurses-base libxml2 dbus dhcpv6-client zip slang hdparm shadow-utils pam tzdata tar kpartx python-urlgrabber db4 rpm-libs libvolume_id groff dhclient ncurses rpm-python bind-utils parted fedora-logos bc openssh-clients python-libs wireless-tools libcap pkgconfig make logrotate libsepol pcre dbus-python yum acpid bzip2 filesystem util-linux-ng dirmngr libsemanage tree unzip tcp_wrappers-libs cracklib openssl python-iniparse elfutils-libelf device-mapper libacl basesystem net-tools acl ncurses-libs isomd5sum openssh keyutils-libs wget usermode sudo libuser glibc-common udev selinux-policy-targeted symlinks libedit attr sed rhpl nss_db MAKEDEV iptables-ipv6 cyrus-sasl info python traceroute passwd libgcrypt setup system-config-network-tui popt eject ntfs-3g gdbm openssh-server diffutils vim-minimal device-mapper-libs libcurl gamin expat device-mapper-multipath rng-utils libstdc++ dbus-libs gzip procmail sendmail nspr mingetty iptables libnl libksba openldap libgcc linux-atm-libs lvm2 bzip2-libs kbd sqlite e2fsprogs libdhcp4client yum-utils at ethtool libusb ustr nss e2fsprogs-libs gpm authconfig cronie libgpg-error fedora-release module-init-tools ConsoleKit-libs cpio

Condensed list (42 packages):
tree unzip which eject file ntfs-3g openssh-server device-mapper-multipath rng-utils nc sendmail acl system-config-firewall-tui setuptool tcpdump dhcpv6-client zip hdparm wget sudo kbd grub selinux-policy-targeted time dhclient symlinks attr bind-utils kernel nss_db at yum-utils cyrus-sasl-plain anacron bc openssh-clients gpm traceroute authconfig cronie man acpid