diff options
Diffstat (limited to 'pkgs/build-support/vm/deb/deb-closure.pl')
-rw-r--r-- | pkgs/build-support/vm/deb/deb-closure.pl | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/pkgs/build-support/vm/deb/deb-closure.pl b/pkgs/build-support/vm/deb/deb-closure.pl new file mode 100644 index 000000000000..f35af6ca2dad --- /dev/null +++ b/pkgs/build-support/vm/deb/deb-closure.pl @@ -0,0 +1,162 @@ +use strict; +use Dpkg::Cdata; +use Dpkg::Deps; + +my $packagesFile = shift @ARGV; +my $urlPrefix = shift @ARGV; +my @toplevelPkgs = @ARGV; + +my %packages; + + +# Parse the Packages file. +open PACKAGES, "<$packagesFile" or die; + +while (1) { + my $cdata = parsecdata(\*PACKAGES, $packagesFile); + last unless defined $cdata; + #print $cdata->{Package}, "\n"; + die unless defined $cdata->{Package}; + $packages{$cdata->{Package}} = $cdata; +} + +close PACKAGES; + + +# Flatten a Dpkg::Deps dependency value into a list of package names. +sub getDeps { + my $deps = shift; + #print "$deps\n"; + if ($deps->isa('Dpkg::Deps::AND')) { + my @res = (); + foreach my $dep ($deps->get_deps()) { + push @res, getDeps($dep); + } + return @res; + } elsif ($deps->isa('Dpkg::Deps::OR')) { + # Arbitrarily pick the first alternative. + return getDeps(($deps->get_deps())[0]); + } elsif ($deps->isa('Dpkg::Deps::Simple')) { + return ($deps->{package}); + } else { + die "unknown dep type"; + } +} + + +# Process the "Provides" fields to be able to resolve virtual dependencies. +my %provides; + +foreach my $cdata (values %packages) { + next unless defined $cdata->{Provides}; + my @provides = getDeps(Dpkg::Deps::parse($cdata->{Provides})); + foreach my $name (@provides) { + #die "conflicting provide: $name\n" if defined $provides{$name}; + $provides{$name} = $cdata->{Package}; + } +} + + +# Determine the closure of a package. +my %donePkgs; +my %depsUsed; +my @order = (); + +sub closePackage { + my $pkgName = shift; + print STDERR ">>> $pkgName\n"; + my $cdata = $packages{$pkgName}; + + if (!defined $cdata) { + die "unknown (virtual) package $pkgName" + unless defined $provides{$pkgName}; + print STDERR "virtual $pkgName: using $provides{$pkgName}\n"; + $pkgName = $provides{$pkgName}; + $cdata = $packages{$pkgName}; + } + + die "unknown package $pkgName" unless defined $cdata; + return if defined $donePkgs{$pkgName}; + $donePkgs{$pkgName} = 1; + + if (defined $cdata->{Provides}) { + foreach my $name (getDeps(Dpkg::Deps::parse($cdata->{Provides}))) { + $provides{$name} = $cdata->{Package}; + } + } + + my @depNames = (); + + if (defined $cdata->{Depends}) { + print STDERR " $pkgName: $cdata->{Depends}\n"; + my $deps = Dpkg::Deps::parse($cdata->{Depends}); + die unless defined $deps; + push @depNames, getDeps($deps); + } + + if (defined $cdata->{'Pre-Depends'}) { + print STDERR " $pkgName: $cdata->{'Pre-Depends'}\n"; + my $deps = Dpkg::Deps::parse($cdata->{'Pre-Depends'}); + die unless defined $deps; + push @depNames, getDeps($deps); + } + + foreach my $depName (@depNames) { + closePackage($depName); + } + + push @order, $pkgName; + $depsUsed{$pkgName} = \@depNames; +} + +foreach my $pkgName (@toplevelPkgs) { + closePackage $pkgName; +} + + +# Generate the output Nix expression. +print "# This is a generated file. Do not modify!\n"; +print "# Following are the Debian packages constituting the closure of: @toplevelPkgs\n\n"; +print "{fetchurl}:\n\n"; +print "[\n\n"; + +# Output the packages in strongly connected components. +my %done; +my %forward; +my $newComponent = 1; +foreach my $pkgName (@order) { + $done{$pkgName} = 1; + my $cdata = $packages{$pkgName}; + my @deps = @{$depsUsed{$pkgName}}; + foreach my $dep (@deps) { + $dep = $provides{$dep} if defined $provides{$dep}; + $forward{$dep} = 1 unless defined $done{$dep}; + } + delete $forward{$pkgName}; + + print " [\n\n" if $newComponent; + $newComponent = 0; + + print " (fetchurl {\n"; + print " url = $urlPrefix/$cdata->{Filename};\n"; + print " sha256 = \"$cdata->{SHA256}\";\n"; + print " })\n"; + print "\n"; + + if (keys %forward == 0) { + print " ]\n\n"; + $newComponent = 1; + } +} + +foreach my $pkgName (@order) { + my $cdata = $packages{$pkgName}; +} + +print "]\n"; + +if ($newComponent != 1) { + print STDERR "argh: ", keys %forward, "\n"; + exit 1; +} + |