]> git.donarmstrong.com Git - wannabuild.git/blobdiff - bin/wanna-build
Implement transactions
[wannabuild.git] / bin / wanna-build
index 7b9c4ea77176f817e7f00cac75557efd9f3e879b..5689f7b704a62d1a568e3d7e06c1e3bc8a663db1 100755 (executable)
@@ -37,6 +37,7 @@ package main;
 use strict;
 use POSIX;
 use FileHandle;
+use File::Copy;
 use GDBM_File;
 use MLDBM qw(GDBM_File Storable);
 use WannaBuild;
@@ -45,10 +46,11 @@ our ($verbose, $mail_logs, $list_order, $list_state,
     $curr_date, $op_mode, $user, $real_user, $distribution,
     $fail_reason, $opt_override, $import_from, $export_to, $opt_create_db,
     $transactlog, %db, %otherdb, %otherdb_lock, %prioval, %sectval,
-    $info_all_dists, $hostname, $arch,
+    $info_all_dists, $arch,
     $category, %catval, %short_category,
-    $short_date, $list_min_age, $dbbase, $host_set, @curr_time,
-    $build_priority, %new_vers, $binNMUver, %merge_srcvers, %merge_binsrc);
+    $short_date, $list_min_age, $dbbase, @curr_time,
+    $build_priority, %new_vers, $binNMUver, %merge_srcvers, %merge_binsrc,
+    $lock_for_pid, $transactional);
 
 # global vars
 $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin";
@@ -58,6 +60,8 @@ $mail_logs = "";
 $curr_date = strftime("%Y %b %d %H:%M:%S",@curr_time);
 $short_date = strftime("%m/%d/%y",@curr_time);
 $| = 1;
+$lock_for_pid = -1; # -1 means normal procedure
+$transactional = 0; # 0 means: work on main copy
 
 # map program invocation names to operation modes
 my %prognames = ( "uploaded-build"  => "set-uploaded",
@@ -144,6 +148,7 @@ my %options =
                           $distribution = "";
                   }
                   else {
+                          $distribution = "oldstable"   if $distribution eq "o";
                           $distribution = "stable"   if $distribution eq "s";
                           $distribution = "testing"  if $distribution eq "t";
                           $distribution = "unstable" if $distribution eq "u";
@@ -181,6 +186,12 @@ my %options =
         # special actions
         import         => { arg => \$import_from, mode => "import" },
         export         => { arg => \$export_to, mode => "export" },
+        "lock-for"     => { arg => \$lock_for_pid, mode => "lock-for" },
+        "unlock-for"   => { arg => \$lock_for_pid, mode => "unlock-for" },
+        "act-on-behalve-of" => { arg => \$lock_for_pid },
+        "start-transaction" => { mode => "start-transaction" },
+        "commit-transaction" => { mode => "commit-transaction" },
+        "transactional" => { flag => \$transactional },
         "manual-edit"  => { mode => "manual-edit" },
         "create-maintenance-lock" => { mode => "maintlock-create" },
         "remove-maintenance-lock" => { mode => "maintlock-remove" },
@@ -245,7 +256,8 @@ if ($verbose) {
 }
 
 if (!@ARGV && !isin( $op_mode, qw(list merge-quinn merge-partial-quinn import export
-                                 merge-packages manual-edit maintlock-create
+                                 merge-packages manual-edit maintlock-create lock-for unlock-for
+                                 start-transaction commit-transaction
                                  merge-sources maintlock-remove clean-db))) {
        warn "No packages given.\n";
        usage();
@@ -297,12 +309,43 @@ if ($op_mode eq "maintlock-remove") {
 waitfor_maintlock() if $op_mode !~ /^(?:merge-|clean-db$)/;
 
 if (!-f db_filename( $distribution ) && !$opt_create_db) {
-       die "Database for $distribution doesn't exist\n";
+       if ($transactional) {
+               die "No running transaction for $distribution\n";
+       } else {
+               die "Database for $distribution doesn't exist\n";
+       }
+}
+
+# Locking for another process means that a longer running process (most likely
+# wb) wants to do several steps at once, and manages the locks.
+if ($op_mode eq "lock-for") {
+       lock_db( $distribution );
+       exit 0;
+}
+if ($op_mode eq "unlock-for") {
+       unlock_db( $distribution );
+       exit 0;
 }
+
 lock_db( $distribution );
+
+if ($op_mode eq "start-transaction") {
+       copy ( db_filename_master( $distribution ), db_filename_transaction( $distribution ))
+               or die "Copy failed: $!";
+       exit 0;
+}
+
+if ($op_mode eq "commit-transaction") {
+       move ( db_filename_transaction( $distribution ), db_filename_master( $distribution ))
+               or die "Copy failed: $!";
+       exit 0;
+}
+
 END {
-    untie %db;
-       unlock_db( $distribution );
+       untie %db;
+       if ($lock_for_pid == -1) {
+               unlock_db( $distribution );
+       }
        foreach (keys %conf::distributions) {
                untie %{$otherdb{$_}} if tied(%{$otherdb{$_}});
                unlock_db( $_ ) if $otherdb_lock{$_};
@@ -440,9 +483,15 @@ sub process {
        }
        if (not -t and $user =~ /-/) {
                my $userinfo = $db{'_userinfo'};
+               $userinfo = {} if (!defined($userinfo));
+
                my $ui = $userinfo->{$user};
+               $ui = {} if (!defined($ui));
+
+               $ui->{'Last-Seen'} = $curr_date;
+               $ui->{'User'} = $user;
 
-               $userinfo->{$user}->{'Last-Seen'} = $curr_date;
+               $userinfo->{$user} = $ui;
                $db{'_userinfo'} = $userinfo;
        }
 }
@@ -1620,36 +1669,55 @@ BEGIN {
                                 'debian-installer'     => -199,
                                 base                   => -198,
                                 devel                  => -197,
-                                shells                 => -196,
-                                perl                   => -195,
-                                python                 => -194,
-                                graphics               => -193,
-                                admin                  => -192,
-                                utils                  => -191,
-                                x11                    => -190,
-                                editors                => -189,
-                                net                    => -188,
-                                mail                   => -187,
-                                news                   => -186,
-                                tex                    => -185,
-                                text                   => -184,
-                                web                    => -183,
-                                doc                    => -182,
-                                interpreters           => -181,
-                                gnome                  => -180,
-                                kde                    => -179,
-                                games                  => -178,
-                                misc                   => -177,
-                                otherosfs              => -176,
-                                oldlibs                => -175,
-                                libdevel               => -174,
-                                sound                  => -173,
-                                math                   => -172,
-                                science                => -171,
-                                comm                   => -170,
-                                electronics            => -169,
-                                hamradio               => -168,
-                                embedded               => -166,
+                                kernel                 => -196,
+                                shells                 => -195,
+                                perl                   => -194,
+                                python                 => -193,
+                                graphics               => -192,
+                                admin                  => -191,
+                                utils                  => -190,
+                                x11                    => -189,
+                                editors                => -188,
+                                net                    => -187,
+                                httpd                  => -186,
+                                mail                   => -185,
+                                news                   => -184,
+                                tex                    => -183,
+                                text                   => -182,
+                                web                    => -181,
+                                vcs                    => -180,
+                                doc                    => -179,
+                                localizations          => -178,
+                                interpreters           => -177,
+                                ruby                   => -176,
+                                java                   => -175,
+                                ocaml                  => -174,
+                                lisp                   => -173,
+                                haskell                => -172,
+                                'cli-mono'             => -171,
+                                gnome                  => -170,
+                                kde                    => -169,
+                                xfce                   => -168,
+                                gnustep                => -167,
+                                database               => -166,
+                                video                  => -165,
+                                debug                  => -164,
+                                games                  => -163,
+                                misc                   => -162,
+                                fonts                  => -161,
+                                otherosfs              => -160,
+                                oldlibs                => -159,
+                                libdevel               => -158,
+                                sound                  => -157,
+                                math                   => -156,
+                                'gnu-r'                => -155,
+                                science                => -154,
+                                comm                   => -153,
+                                electronics            => -152,
+                                hamradio               => -151,
+                                embedded               => -150,
+                                php                    => -149,
+                                zope                   => -148,
        );
        foreach my $i (keys %sectval) {
                $sectval{"contrib/$i"} = $sectval{$i}+40;
@@ -1913,6 +1981,10 @@ sub lock_db {
                                        unlink( $lockfile );
                                        goto repeat;
                                }
+                               if ($pid == $lock_for_pid) {
+                                       # We are allowed to use this lock.
+                                       return;
+                               }
                                warn "Database locked by $usr -- please wait\n" if $try == 0;
                        }
                        if (++$try > 200) {
@@ -1925,7 +1997,8 @@ sub lock_db {
                }
                die "Can't create lock file $lockfile: $!\n";
        }
-       F->print("$$ $real_user\n");
+       my $pid = $lock_for_pid == -1 ? $$ : $lock_for_pid;
+       F->print("$pid $real_user\n");
        F->close();
 }
 
@@ -2039,8 +2112,19 @@ sub read_db {
                }
                check_entry( \%thispkg );
                # add to db
-               $name = $thispkg{'Package'};
-               $db{$name} = \%thispkg;
+               if (exists($thispkg{'Package'})) {
+                       $name = $thispkg{'Package'};
+                       $db{$name} = \%thispkg;
+               }
+               elsif(exists($thispkg{'User'})) {
+                       my $userinfo = $db{'_userinfo'};
+                       $userinfo = {} if (!defined($userinfo));
+
+                       $name = $thispkg{'User'};
+                       $userinfo->{$name} = \%thispkg;
+
+                       $db{'_userinfo'} = $userinfo;
+                }
        }
        close( F );
        print "done\n" if $verbose >= 1;
@@ -2053,10 +2137,13 @@ sub check_entry {
        return if $op_mode eq "manual-edit"; # no checks then
        
        # check for required fields
+       if (exists $pkg->{'User'}) {
+               return;
+       }
        if (!exists $pkg->{'Package'}) {
                print STDERR "Bad entry: ",
                          join( "\n", map { "$_: $pkg->{$_}" } keys %$pkg ), "\n";
-               die "Database entry lacks Package: field\n";
+               die "Database entry lacks Package or User: field\n";
        }
        if (!exists $pkg->{'Version'}) {
                die "Database entry for $pkg->{'Package'} lacks Version: field\n";
@@ -2084,13 +2171,29 @@ sub write_db {
 
        foreach $name (sort keys %db) {
                my $pkg = $db{$name};
-               foreach $key (keys %{$pkg}) {
-                       my $val = $pkg->{$key};
-                       chomp( $val );
-                       $val =~ s/\n/\n /g;
-                       print F "$key: $val\n";
+               if ($name eq '_userinfo') {
+                       foreach $user (sort keys %{$pkg}) {
+                           my $ui = $pkg->{$user};
+                           print F "User: $user\n"
+                               if (!defined($ui->{'User'}));
+                           foreach $key (keys %{$ui}) {
+                               my $val = $ui->{$key};
+                               chomp($val);
+                               $val =~ s/\n/\n /g;
+                               print F "$key: $val\n";
+                           }
+                           print F "\n";
+                       }
+               }
+               else {
+                       foreach $key (keys %{$pkg}) {
+                               my $val = $pkg->{$key};
+                               chomp( $val );
+                               $val =~ s/\n/\n /g;
+                               print F "$key: $val\n";
+                       }
+                       print F "\n";
                }
-               print F "\n";
        }
        close( F );
        print "done\n" if $verbose >= 1;
@@ -2177,14 +2280,11 @@ sub send_mail {
        my $text = shift;
 
        my $from = $conf::db_maint;
+       my $domain = $conf::buildd_domain;
 
-       if ($host_set != 1) {
-               chomp( $hostname = `/bin/hostname -f` );
-               $host_set = 1;
-       }
-       $from .= "\@$hostname" if $from !~ /\@/;
+       $from .= "\@$domain" if $from !~ /\@/;
 
-       $to .= '@' . $hostname if $to !~ /\@/;
+       $to .= '@' . $domain if $to !~ /\@/;
        $text =~ s/^\.$/../mg;
        local $SIG{'PIPE'} = 'IGNORE';
        open( PIPE,  "| $conf::mailprog -oem $to" )
@@ -2197,9 +2297,18 @@ sub send_mail {
 }
 
 sub db_filename {
+       my $dist = shift;
+       return $transactional ? db_filename_transaction($dist) : db_filename_master($dist);
+}
+
+sub db_filename_master {
        my $dist = shift;
        return "$conf::basedir/$conf::dbbase-$dist";
 }
+sub db_filename_transaction {
+       my $dist = shift;
+       return "$conf::basedir/$conf::dbbase-$dist-transaction";
+}
 
 # for parsing input to dep-wait
 sub parse_deplist {
@@ -2452,8 +2561,8 @@ Options:
     -u, --uploaded: Record in the database that the packages build
         correctly and were uploaded.
     -n, --no-build: Record in the database that the packages aren't
-        desired for m68k and shouldn't appear in listings even if
-        they're out of date.
+        desired for this architecture and shouldn't appear in listings even
+       if they're out of date.
     --dep-wait: Record in the database that the packages are waiting
         for some source dependencies to become available
     --merge-quinn: Merge quinn-diff output into database.
@@ -2475,6 +2584,16 @@ Options:
         automatically choosen
     --import FILE: Import database from a ASCII file FILE
     --export FILE: Export database to a ASCII file FILE
+    --lock-for PID: Locks the database for the process with this pid
+    --unlock-for PID: Unlocks the database for the process with this pid
+    --act-on-behalve-of PID: Ignores the log (if it is held by this pid)
+    --start-transaction: Creates a copy of the state of the database, for
+       use with --transactional. This overrides any previous uncommited
+       transaction. Should only be used after --lock-for
+    --commit-transaction: Atomically moves the copy back to the main, thus
+       commiting the changes
+    --transactional: Flag to indicate that we want to work on the copy
+
 The remaining arguments (depending on operation) usually start with
 "name_version", the trailer is ignored. This allows to pass the names
 of .dsc files, for which file name completion can be used.