Update of /cvsroot/fink/scripts/buildfink In directory sc8-pr-cvs5.sourceforge.net:/tmp/cvs-serv26835
Modified Files: buildfink Log Message: Here's a shot at support for building only a subset of packages... Index: buildfink =================================================================== RCS file: /cvsroot/fink/scripts/buildfink/buildfink,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- buildfink 8 Aug 2006 19:25:28 -0000 1.28 +++ buildfink 19 Oct 2006 20:48:51 -0000 1.29 @@ -1,6 +1,6 @@ #!/usr/bin/perl -#Copyright (c) 2005 Apple Computer, Inc. All Rights Reserved. +#Copyright (c) 2005-2006 Apple Computer, Inc. All Rights Reserved. # #This program is free software; you can redistribute it and/or modify #it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ =head1 USAGE - buildfink [-n] [--infofilter SCRIPT] [--patchdir DIR] [--skip PACKAGE] [--skip PACKAGE] [--validate] [--build-as-nobody] [--max-log-size [P:]N] [--max-build-time [P:]T] [FINKDIR OUTDIR + buildfink [-n] [--infofilter SCRIPT] [--patchdir DIR] [--skip PACKAGE] [--skip PACKAGE] [--validate] [--build-as-nobody] [--max-log-size [P:]N] [--max-build-time [P:]T] [--packages PKGLIST] [--rebuild-dependents] [--dirty] [FINKDIR OUTDIR] buildfink [-r CHECKPOINT] C<buildfink> builds every package in Fink, taking care of things like avoiding repeated building @@ -71,6 +71,15 @@ C<--max-build-time openoffice.org:24h> would specify a 24-hour limit for openoffice.org. +Normally, buildfink will attempt to build every package it knows about. To +build only a subset of packages, give C<--packages PKGLIST>, where C<PKGLIST> +is a comma-separated list of packages. Packages necessary to satisfy +dependencies of these will be installed or built as necessary. If operating in +this mode, you may also want the C<--dirty> option to avoid purging all +non-essential packages before performing each build. The +C<--rebuild-dependents> option will add any packages which depend on anything +in C<PKGLIST> . + =head2 CHECKPOINTS Sometimes there will be system issues partway through a build. For instance, a recalcitrant @@ -93,7 +102,7 @@ use lib "$Bin"; use FinkLib; -our($Bin, $FinkConfig, $FinkDir, $rundir, $dryrun, $infofilter, $patchdir, @skiplist, $checkpoint, $DoValidate, $BuildNobody); +our($Bin, $FinkConfig, $FinkDir, $rundir, $dryrun, $infofilter, $patchdir, @skiplist, $checkpoint, $DoValidate, $BuildNobody, $Dirty, $RebuildDeps, $BuildAll); our $VERSION = '$Revision$'; our $max_build_time = 60*60*4; @@ -139,6 +148,16 @@ } } +# Keys will be package names. Values will be: +my %pkglist; +use constant PKGSTATUS_INSTALLED => 3; +use constant PKGSTATUS_REBUILD => 2; +use constant PKGSTATUS_INSTALL => 1; +use constant PKGSTATUS_PROCESSING => 0; +use constant PKGSTATUS_FAILED => -1; +use constant PKGSTATUS_SKIP => -2; + +$BuildAll = 1; my $opts_ok = GetOptions( "n" => \$dryrun, "infofilter=s" => \$infofilter, @@ -146,6 +165,12 @@ "skip=s" => [EMAIL PROTECTED], "r=s" => \$checkpoint, "validate" => \$DoValidate, + "dirty" => \$Dirty, + "rebuild-dependents" => \$RebuildDeps, + "packages=s" => sub { + %pkglist = map { $_ => PKGSTATUS_REBUILD } filterSplitoffs(split(/,/, $_[1])); + $BuildAll = 0; + }, "build-as-nobody:s" => \$BuildNobody, "max-build-time=s" => \&limit_arg, "max-log-size=s" => \&limit_arg @@ -191,44 +216,56 @@ die "See 'perldoc $0' for more information.\n"; } - if($checkpoint) { restoreCheckpoint($checkpoint); exit(); } - restoreSystem(); prepSystem(); -FinkLib::purgeNonEssential(); +FinkLib::purgeNonEssential() unless $Dirty; FinkLib::readPackages(); removeBuildLocks(); -my(@pkglist) = Fink::Package->list_packages(); +%pkglist = map { $_ => PKGSTATUS_REBUILD } filterSplitoffs(Fink::Package->list_packages()) if $BuildAll; +foreach (filterSplitoffs(@skiplist)) { + $pkglist{$_} = PKGSTATUS_SKIP; + logPackageFail($_, "Package is on the skip list."); +} -if(!$dryrun) { - # Then copy the .info files to our private repository and patch them if necessary. - patchPackages(@pkglist); +# Don't try to install uninstalled virtual packages. +# We can't use them to satisfy dependencies and we can't build them... +my $vpinfo = Fink::VirtPackage->list(); +while(my($pkgname, $hash) = each(%$vpinfo)) { + if($hash->{status} !~ / installed$/) { + $pkglist{$pkgname} = PKGSTATUS_SKIP; + logPackageFail($_, "Package is an uninstalled virtual package."); + } else { + $pkglist{$pkgname} = PKGSTATUS_INSTALLED; + } +} - # Only let Fink see our modified packages - injectPackages(); + +if(!$BuildAll and $RebuildDeps) { + foreach my $pkg (keys %pkglist) { + my @deps = getDependsRecursive($pkg); + foreach my $dep (@deps) { + $pkglist{$dep} = PKGSTATUS_REBUILD; + } + } } -# Now order the list of packages in dependency order, so that all of X's -# dependencies come before X. Filter out all of the split-offs, so we only -# build root packages, and then remove everything on the skip list and anything -# which depends on anything on the skip list. -my(%deps) = getAllDepends([EMAIL PROTECTED]); -my(@orderedPkgs) = filterSplitOffs(orderByDepends([EMAIL PROTECTED], \%deps)); +if(!$dryrun) { + # Then copy the .info files to our private repository and patch them if necessary. + patchPackages(keys %pkglist); -if($dryrun) { - print join("\n", @orderedPkgs), "\n"; - exit; + # Only let Fink see our modified packages + injectPackages() if $BuildAll; } # Now do the run -initCheckpoint([EMAIL PROTECTED], \%deps, {}); -FinkLib::installEssentials(); -buildAll([EMAIL PROTECTED], [EMAIL PROTECTED], \%deps, {}); +initCheckpoint(\%pkglist) unless $dryrun; +FinkLib::installEssentials() unless $dryrun; +buildAll(\%pkglist); doLog("Done building"); restoreSystem(); @@ -486,157 +523,233 @@ } } -# Build all packages, skipping any with failed deps -# pkglist is a list of package names to build in order. -# skiplist is a list of package names to never build. -sub buildAll { - my($pkgs, $skiplist, $deps, $failures) = @_; - my %skiphash = map {$_ => 1} @$skiplist; +sub setPackageStatus { + my($pkglist, $pkg, $status) = @_; + $pkglist->{$pkg} = $status; + updaetCheckpoint($pkg => $status); +} - # First, we set all uninstalled virtual packages as 'failed'. - # We can't use them to satisfy dependencies and we can't build them... - my $vpinfo = Fink::VirtPackage->list(); - while(my($pkgname, $hash) = each(%$vpinfo)) { - $failures->{$pkgname} = 1 if $hash->{status} !~ / installed$/; - } +sub setPackageFail { + my($pkglist, $pkg, $reason) = @_; + logPackageFail($pkg, $reason); + setPackageStatus($pkglist, $pkg, PKGSTATUS_FAILED); +} - # Also set packages on the skiplist to failed - $failures->{$_} = 1 foreach keys %skiphash; +# Try to build an individual package. +sub recurseOnDepends { + my($pkglist, $pkg, $install, $finkfiles) = @_; + $pkglist->{$pkg} = PKGSTATUS_PROCESSING; + doLog("Trying to satisfy $pkg"); - my %finkfiles; - if($DoValidate) { - Fink::Config::set_options({"Pedantic" => 1}); + my $obj; + eval { + $obj = Fink::PkgVersion->match_package($pkg); + }; + if($@ or !$obj) { + setPackageFail($pkglist, $pkg, "Couldn't get package object: $@"); + return; + } - # One of the validation steps is to identify files left in /sw - # by the build process. - find({no_chdir => 1, wanted => sub { - $finkfiles{$File::Find::name} = 1; - }}, $FinkDir); + if($obj->is_type('dummy')) { + doLog("$pkg is a dummy."); + setPackageStatus($pkglist, $pkg, PKGSTATUS_INSTALLED); + return 1; } - my @newfails; - PACKAGE: foreach my $pkg(@$pkgs) { - doLog("Thinking about building $pkg"); + # Build deps, and maybe run deps + my @deps; + eval { + @deps = $obj->resolve_depends(2, "depends"); + push @deps, $obj->resolve_depends(0, "depends") if $install; + }; + if($@) { + setPackageFail($pkglist, $pkg, "Couldn't get depends: $@"); + return; + } - my $skipcause = ""; - if($skiphash{$pkg}) { - $skipcause = "$pkg is on the skip list"; - } else { - my $dep = findFailedDep($pkg, $deps, $failures); - $skipcause = "Dependency $dep failed to build" if $dep; + # @deps is in conjunctive normal form. That is, it is a list like: + # {{A ^ B ^ C} v {D ^ E} v {F}} + # In other words, a list of alternatives, and each alternative is a + # series of packages which must all be satisfied. + my $satisfied = 0; + my @faildep; + CHECKSAT: foreach my $alternative (@deps) { + foreach my $altdep (@$alternative) { + my $depstat = $pkglist->{$altdep}; + $depstat = PKGSTATUS_INSTALL unless defined($depstat); + if($depstat == PKGSTATUS_FAILED or $depstat == PKGSTATUS_PROCESSING) { + push @faildep, $altdep; + next CHECKSAT; + } } - if($skipcause) { - logPackageFail($pkg, $skipcause); - next; + # This alternative is satisfiable + foreach my $altdep (@$alternative) { + $pkglist->{$altdep} = PKGSTATUS_INSTALL if !defined($pkglist->{$altdep}); + next if $pkglist->{$altdep} == PKGSTATUS_INSTALLED; + recurseOnDepends($pkglist, filterSplitoffs($altdep), 1, $finkfiles); + if($pkglist->{$altdep} == PKGSTATUS_FAILED) { + push @faildep, $altdep; + next CHECKSAT; + } } - my $obj; - eval { - $obj = Fink::PkgVersion->match_package($pkg); - }; - if($@ or !$obj) { - doLog("Couldn't get object for $pkg: $@"); - next; - } + $satisfied = 1; + last; + } - next if $obj->is_type('dummy'); + if(!$satisfied) { + logPackageFail($pkg, "Can't figure out how to build. Unsatisfied dependencies: " . join(" ", sort @faildep)); + return; + } - if($DoValidate) { - open(VAL, ">>", "$rundir/validate/$pkg") or die "Couldn't open validation log for $pkg: $!\n"; - my $oldfh = select(VAL); - Fink::Validation::validate_info_file($obj->get_info_filename()); - select($oldfh); - close(VAL); - } + if($DoValidate) { + open(VAL, ">>", "$rundir/validate/$pkg") or die "Couldn't open validation log for $pkg: $!\n"; + my $oldfh = select(VAL); + Fink::Validation::validate_info_file($obj->get_info_filename()); + select($oldfh); + close(VAL); + } - doLog("Building package $pkg..."); - my $srcdir = $Fink::Config::buildpath; # Suppress "used only once" warning - $srcdir = "$Fink::Config::buildpath/" . $obj->get_fullname(); + doLog("Building package $pkg..."); + my $srcdir = $Fink::Config::buildpath; # Suppress "used only once" warning + $srcdir = "$Fink::Config::buildpath/" . $obj->get_fullname(); - my $buildcmd = "printf '\n\n' | fink --yes"; - $buildcmd .= " --build-as-nobody" if $BuildNobody; - $buildcmd .= " rebuild $pkg 2>&1"; - my $ret = doBuild($buildcmd, $pkg); + my $buildcmd = "printf '\n\n' | fink --yes "; + $buildcmd .= "--build-as-nobody " if $BuildNobody; + if($pkglist->{$pkg} == PKGSTATUS_REBUILD) { + $buildcmd .= "rebuild "; + } else { + $buildcmd .= "install "; + } + $buildcmd .= "$pkg 2>&1"; + my $ret = doBuild($buildcmd, $pkg); - if($ret != 0 and defined($BuildNobody) and $BuildNobody eq "try") { - $buildcmd =~ s/ --build-as-nobody//; - move("$rundir/logs/$pkg.log", "$rundir/logs/$pkg.log.nobody"); - doLog("Build of $pkg failed, trying as root..."); - $ret = doBuild($buildcmd, $pkg); - if($ret != 0) { - unlink("$rundir/logs/$pkg.log.nobody"); - } else { - move("$rundir/logs/$pkg.log.nobody", "$rundir/nobody/$pkg.log"); - } - } - + if($ret != 0 and defined($BuildNobody) and $BuildNobody eq "try") { + $buildcmd =~ s/ --build-as-nobody//; + move("$rundir/logs/$pkg.log", "$rundir/logs/$pkg.log.nobody"); + doLog("Build of $pkg failed, trying as root..."); + $ret = doBuild($buildcmd, $pkg); if($ret != 0) { - doLog("Build of $pkg failed!"); - $failures->{$pkg} = 1; - push @newfails, $pkg; + unlink("$rundir/logs/$pkg.log.nobody"); + } else { + move("$rundir/logs/$pkg.log.nobody", "$rundir/nobody/$pkg.log"); + } + } - # Also, any splitoffs of this package have failed. - my @relatives = getRelatives($obj); - foreach (@relatives) { - my $name = $_->get_name(); - $failures->{$name} = 1; - push @newfails, $name; - } + if($ret != 0) { + doLog("Build of $pkg failed!"); + my @failpkgs = $pkg; + + # Also, any splitoffs of this package have failed. + my @relatives = getRelatives($obj); + foreach (@relatives) { + my $name = $_->get_name(); + push @failpkgs, $pkg; system("mv", $srcdir, "$rundir/src/$pkg") or doLog("Couldn't move $srcdir to $rundir/src/$pkg: $!"); - } else { - doLog("Build of $pkg succeeded!"); - system("rm", "-rf", $srcdir); + } + $pkglist->{$_} = PKGSTATUS_FAILED foreach @failpkgs; + updateCheckpoint(map { $_ => PKGSTATUS_FAILED } @failpkgs); + return; + } else { + doLog("Build of $pkg succeeded!"); + system("rm", "-rf", $srcdir); - my $deb = $obj->get_debname(); + my $deb = $obj->get_debname(); + move(readlink("$FinkDir/fink/debs/$deb"), "$rundir/pkginfo/binary-darwin-powerpc/$deb"); + unlink("$FinkDir/fink/debs/$deb"); + symlink("$rundir/pkginfo/binary-darwin-powerpc/$deb", "$FinkDir/fink/debs/$deb"); + + my @okpkgs = $pkg; + foreach my $relative(getRelatives($obj)) { + push @okpkgs, $relative->get_name(); + + my $deb = $relative->get_debname(); move(readlink("$FinkDir/fink/debs/$deb"), "$rundir/pkginfo/binary-darwin-powerpc/$deb"); unlink("$FinkDir/fink/debs/$deb"); symlink("$rundir/pkginfo/binary-darwin-powerpc/$deb", "$FinkDir/fink/debs/$deb"); + } - foreach my $relative(getRelatives($obj)) { - my $deb = $relative->get_debname(); - move(readlink("$FinkDir/fink/debs/$deb"), "$rundir/pkginfo/binary-darwin-powerpc/$deb"); - unlink("$FinkDir/fink/debs/$deb"); - symlink("$rundir/pkginfo/binary-darwin-powerpc/$deb", "$FinkDir/fink/debs/$deb"); + $pkglist->{$_} = PKGSTATUS_INSTALLED foreach @okpkgs; + updateCheckpoint(map { $_ => PKGSTATUS_INSTALLED } @okpkgs); + } + + FinkLib::purgeNonEssential() unless $Dirty; + + if($DoValidate) { + my @killqueue; + + find({no_chdir => 1, wanted => sub { + if(/\.deb$/ or $_ =~ /fink\.build$/ or $File::Find::name eq "$FinkDir/var/lib/fink/finkinfodb") { + $File::Find::prune = 1; + } elsif(!$finkfiles->{$File::Find::name}) { + doValidateWarn($pkg, "Leftover file $File::Find::name"); + push @killqueue, $File::Find::name; } + }}, $FinkDir); + + #system("rm", "-rf", @killqueue); + $finkfiles->{$_} = 1 foreach @killqueue; + + open(VAL, ">>", "$rundir/validate/$pkg") or die "Couldn't open validation log for $pkg: $!\n"; + my $oldfh = select(VAL); + + my $deb = "$rundir/pkginfo/binary-darwin-powerpc/" . $obj->get_debname(); + Fink::Validation::validate_dpkg_file($deb) if -f $deb; + foreach my $relative(getRelatives($obj)) { + my $deb = "$rundir/pkginfo/binary-darwin-powerpc/" . $relative->get_debname(); + Fink::Validation::validate_dpkg_file($deb) if -f $deb; } - FinkLib::purgeNonEssential(); + select($oldfh); + close(VAL); + } - if($DoValidate) { - my @killqueue; + return 1; +} - find({no_chdir => 1, wanted => sub { - if(/\.deb$/ or $_ =~ /fink\.build$/ or $File::Find::name eq "$FinkDir/var/lib/fink/finkinfodb") { - $File::Find::prune = 1; - } elsif(!$finkfiles{$File::Find::name}) { - doValidateWarn($pkg, "Leftover file $File::Find::name"); - push @killqueue, $File::Find::name; - } - }}, $FinkDir); +# Try to build packages, adding to pkglist as we encounter deps. +# pkglist is a list of package names to build in order. +# skiplist is a list of package names to never build. +sub buildAll { + my($pkglist) = @_; - #system("rm", "-rf", @killqueue); - $finkfiles{$_} = 1 foreach @killqueue; + my %finkfiles; + if($DoValidate) { + Fink::Config::set_options({"Pedantic" => 1}); + # One of the validation steps is to identify files left in /sw + # by the build process. + find({no_chdir => 1, wanted => sub { + $finkfiles{$File::Find::name} = 1; + }}, $FinkDir); + } - open(VAL, ">>", "$rundir/validate/$pkg") or die "Couldn't open validation log for $pkg: $!\n"; - my $oldfh = select(VAL); + my @newfails; + PACKAGE: while(1) { + my($pkg, $pkgval); + foreach my $p (keys %$pkglist) { + my $v = $pkglist->{$p}; + next unless $v == PKGSTATUS_REBUILD or $v == PKGSTATUS_INSTALL; + $pkg = $p; + $pkgval = $v; + last; + } - my $deb = "$rundir/pkginfo/binary-darwin-powerpc/" . $obj->get_debname(); - Fink::Validation::validate_dpkg_file($deb) if -f $deb; - foreach my $relative(getRelatives($obj)) { - my $deb = "$rundir/pkginfo/binary-darwin-powerpc/" . $relative->get_debname(); - Fink::Validation::validate_dpkg_file($deb) if -f $deb; + if(!$pkg) { + my @unsats = sort grep { $pkglist->{$_} == PKGSTATUS_PROCESSING } keys %$pkglist; + if(@unsats) { + doLog("Couldn't figure out how to build: " . join(", ", @unsats)); + return; + } else { + doLog("Done!"); + return 1; } - - select($oldfh); - close(VAL); } - } continue { - updateCheckpoint(@newfails); - @newfails = (); + + recurseOnDepends($pkglist, $pkg, 0, \%finkfiles); } } @@ -663,181 +776,10 @@ } } -# Get dependency information -sub getAllDepends { - my($pkglist) = @_; - - doLog("Getting dependency graph."); - - my %deps; - foreach my $pkgname (@$pkglist) { - $deps{$pkgname} = getDepends($pkgname); - } - - return %deps; -} - -# Order a list of packages in dependency order. -# pkglist is a listref of package names to order. -sub orderByDepends { - my($pkglist, $deps) = @_; - - doLog("Getting dependency graph."); - - my(@ret, %revdeps); - - foreach my $pkgname (@$pkglist) { - $deps{$pkgname} = getDepends($pkgname); - $deps->{$pkgname}->{ordered} = 0; - my $pkg = $deps->{$pkgname}; - - # Build hash showing which packages are depended on by a given package - foreach my $dep (@{$pkg->{build}}, @{$pkg->{run}}) { - foreach my $deppkg (@$dep) { - $revdeps{$deppkg} ||= []; - push @{$revdeps{$deppkg}}, $pkgname; - } - } - - # Keep track of which dependencies we've satisfied - $pkg->{unsatisfied} = { - build => {map {$_ => 1} map [EMAIL PROTECTED] @{$pkg->{build}} }, - run => {map {$_ => 1} map [EMAIL PROTECTED] @{$pkg->{run}} } - }; - } - - doLog("Ordering packages."); - - # Do a topological sort of the dependency graph. - my @queue; - - # Force dtqa-finkenv to build first. - # This package dumps the environment to standard out during the compile - # phase and does nothing else. We can use it to verify the build environment. - # (e.g. see what environment variables Fink is setting for package builds.) - if($deps->{'dtqa-finkenv'}) { - push @ret, 'dtqa-finkenv'; - $deps->{'dtqa-finkenv'}->{ordered} = 2; - } - - # First, bootstrap it with packages that have no dependencies. - # Those'll be the virtual packages. - my(%virtuals) = %{Fink::VirtPackage->list()}; - push @queue, keys(%virtuals); - - # Also, add in any non-virtual packages with no deps - foreach my $pkgname(keys %deps) { - next if $pkgname eq "dtqa-finkenv"; - my $dep = $deps->{$pkgname}; - next if keys %{$dep->{unsatisfied}->{build}} or keys %{$dep->{unsatisfied}->{run}}; - - push @queue, $pkgname; - - # Also add split-offs of the package. - my $obj; - eval { - $obj = Fink::PkgVersion->match_package($pkgname); - }; - if($@) { - doLog("Couldn't order $pkgname: $@"); - next; - } - - my @relatives = getRelatives($obj); - foreach (@relatives) { - my $name = $_->get_name(); - push @queue, $name; - } - } - - doLog("Processing queue"); - - while(@queue) { - my $pkgname = shift @queue; - - #ordered==2 indicates that the package is installable as well as buildable - next if $deps->{$pkgname}->{ordered} == 2; - - if(!$deps->{$pkgname}->{ordered} and not $virtuals{$pkgname}) { - push @ret, $pkgname; - $deps->{$pkgname}->{ordered} = 1; - } - - # We will place packages on the queue if they are buildable. - # However, the package can only be used to satisfy dependencies - # if it is *installable*. - next if !$virtuals{$pkgname} and keys(%{$deps->{$pkgname}->{unsatisfied}->{run}}); - - $deps->{$pkgname}->{ordered} = 2; - - my @revdeps = @{$revdeps{$pkgname} || []}; - my @provides = ($pkgname); - - my $pkgobj = Fink::Package->package_by_name($pkgname); - - # is_virtual == 1 are the Provides: aliases of regular packages. - # This is not to be confused with is_virtual == 2, which are the - # regular virtual packages. - next if $pkgobj->is_virtual() == 1; - - # We've also satisfied things which depend on somethign we provide - foreach my $provider ($pkgobj->get_all_providers()) { - my $pname = $provider->get_name(); - push @provides, $pname; - push @revdeps, @{$revdeps{$pname} || []}; - } - - # For every package that is depended on by this one... - foreach my $revdep (@revdeps) { - my $dep = $deps->{$revdep}; - - # Remove this one from the list of unsatisfied deps... - foreach my $pname(@provides) { - delete $dep->{unsatisfied}->{run}->{$pname}; - delete $dep->{unsatisfied}->{build}->{$pname}; - } - - # If we've satisfied all builddeps, we can build it. - next if keys(%{$dep->{unsatisfied}->{build}}); - - push @queue, $revdep; - - # And add any splitoffs - my $obj; - eval { - $obj = Fink::PkgVersion->match_package($revdep); - }; - if($@) { - doLog("Couldn't order $obj: $@"); - next; - } - - my @relatives = getRelatives($obj); - foreach (@relatives) { - my $name = $_->get_name(); - push @queue, $name; - } - } - } - - foreach my $pkgname(keys %$deps) { - my $dep = $deps->{$pkgname}; - next if $dep->{ordered}; - my(%unsats) = (%{$dep->{unsatisfied}->{build}}, %{$dep->{unsatisfied}->{run}}); - my $failmsg = "Can't figure out how to build. Unsatisfied dependencies: " . join(" ", sort keys %unsats); - if($dryrun) { - doLog($failmsg); - } else { - logPackageFail($pkgname, $failmsg); - } - } - - return @ret; -} - -# Get list of dependencies for a package -sub getDepends { - my($pkgname) = @_; +# Get a flat list of buidl and run dependencies for a package and its dependencies +sub getDependsRecursive { + my($pkgname, $seen) = @_; + $seen ||= {$pkgname => 1}; # create a variable to hold the main package's object my $pkgobj; @@ -850,11 +792,10 @@ } # now get a list of references to packages - my(@rundeps, @builddeps); - # populate the @deplist with references to arrays of packages + my(@deplist); eval { - @rundeps = $pkgobj->resolve_depends(0, "depends"); - @builddeps = $pkgobj->resolve_depends(2, "depends"); + @deplist = $pkgobj->resolve_depends(0, "depends"); + push @deplist, $pkgobj->resolve_depends(2, "depends"); }; if($@) { doLog("Couldn't get dependencies for $pkgname: $@"); @@ -867,89 +808,16 @@ # # [[foo-dev], [xorg, xfree86, system-xfree86]] # - - my(%ret) = (build => [], run => []); - foreach my $deps ({in => [EMAIL PROTECTED], out => $ret{run}}, {in => [EMAIL PROTECTED], out => $ret{build}}) { - foreach my $dep (@{$deps->{in}}) { - - # If you have two versions of package X, both of them - # will appear in the dependency list; we don't want those - # duplicates, so keep track of what we've seen. - my %alt_seen_pkgs; - - my @alternatives; - - foreach my $dp (@$dep) { - # each $dp is a package object - - # get the name, so we can keep recursing - my $next_dep = $dp->get_name(); - next if $alt_seen_pkgs{$next_dep}++; - - # don't bother recursing if it already has been seen or if it's the same pkg - if(!$next_dep or $next_dep eq $pkgname) { - next; - } else { - push @alternatives, $next_dep; - } - } - - push @{$deps->{out}}, [EMAIL PROTECTED]; - } - } - - # and we're done! - return \%ret; -} - -# Find the first unsatisfiable dependency for a package. -# This may be a string containing multiple alternatives, ala "foo | bar | baz". -# If all dependencies can be satisfied, returns the empty string. -# -# We normally only check the build dependencies, unless the "rundeps" parameter is true. -# We set this parameter when recursing. That's because we only need the builddeps -# satisfied in order to build a package, but those builddeps will need to be installed, -# so they need their runtime depends. -# -# pkgstack is used to avoid circular loops; its a hash of all the packages in the -# recursion chain for this lookup. We'll ignore attempts to check something already -# in the chain. depcache is used to avoid having to do repeated computations on -# the same package. -sub findFailedDep { - my($pkg, $deps, $failures, $rundeps, $pkgstack, $depcache) = @_; - $rundeps ||= 0; - - $pkgstack ||= {}; - $depcache ||= {}; - - return $depcache->{$pkg} if exists($depcache->{$pkg}); - - my @altsets = @{$deps->{$pkg}->{build} || []}; - push @altsets, @{$deps->{$pkg}->{run} || []} if $rundeps; - - foreach my $altset(@altsets) { - my $satisfied = 0; - - foreach my $alt(@$altset) { - next if - $failures->{$alt} or - $pkgstack->{$alt} or - findFailedDep($alt, $deps, $failures, 1, {%$pkgstack, $alt => 1}, $depcache); - - # We found a way to satisfy this set of alternatives. - $satisfied = 1; - last; - } - - if(!$satisfied) { - my $ret = join(" | ", @$altset); - $depcache->{$pkg} = $ret; - return $ret; + my @ret; + foreach my $alternative (@deplist) { + foreach my $dep (@$alternative) { + my $depname = $dep->get_name(); + next unless $seen->{$depname}; + push @ret, $depname; + push @ret, getDependsRecursive($depname, $seen); } } - - $depcache->{$pkg} = ""; - return ""; + return @ret; } # Take a list of package names and filter out the ones which are split-offs. @@ -993,7 +861,7 @@ sub restoreCheckpoint { my($checkpoint) = shift; - my($orderedPkgs, $skiplist, $deps, $failures); + my($pkglist, $skiplist); # We use eval "STRING" so that the variables in the checkpoint are # bound to this sub's lexical scope. @@ -1005,25 +873,25 @@ die "[EMAIL PROTECTED]" if $@; prepSystem(); - injectPackages(); + injectPackages() unless $BuildAll; removeBuildLocks(); doLog("Restored from checkpoint"); @skiplist = @$skiplist; doLog("Building packages"); - buildAll($orderedPkgs, [EMAIL PROTECTED], $deps, $failures); + buildAll(\%$pkglist); doLog("Done building"); restoreSystem(); } sub initCheckpoint { - my($orderedPkgs, $deps, $failures) = @_; + my($pkglist) = @_; open(CHECKPOINT, ">", "$rundir/checkpoint"); print CHECKPOINT Data::Dumper->Dump( - [$FinkDir, $rundir, $BuildNobody, $DoValidate, [EMAIL PROTECTED], $orderedPkgs, $deps, $failures], - [qw(FinkDir rundir BuildNobody DoValidate skiplist orderedPkgs deps failures)] + [$FinkDir, $rundir, $BuildNobody, $BuildAll, $DoValidate, $pkglist], + [qw(FinkDir rundir BuildNobody BuildAll DoValidate pkglist)] ); close CHECKPOINT; @@ -1031,11 +899,10 @@ # Updates the checkpoint after a package build. sub updateCheckpoint { - my(@failed) = @_; + my(%changes) = @_; open(CHECKPOINT, ">>", "$rundir/checkpoint"); - print CHECKPOINT "shift [EMAIL PROTECTED];"; - print CHECKPOINT " \$failures->{'$_'} = 1;" foreach @failed; + print CHECKPOINT "\$pkglist->{$_} = $changes{$_}; " foreach keys %changes; print CHECKPOINT "\n"; close CHECKPOINT; } ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ Fink-commits mailing list Fink-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/fink-commits