Here's a patch to implement bug dependencies. The patch adds two new
fields to the summary files, Blocks and Blocked-By. This information
(should be) kept in sync between blocker and blockee, so only one
summary file needs to be read to determine what bugs a given bug is
blocking, and which ones are blocking it.

The control interface gets a new "blocks" command, which can be used to
tell which bugs a given bug blocks, which is modeled on the tags
command. So:

blocks 10 19 18 17
blocks 10 - 19
blocks 10 = 11

Bugs cannot be merged unless their Blocks and Blocks-By fields are in
the same state. I hope that won't turn out to be *too* annoying. The
alternatives I considered seemed to lead to some bad cases.

Limitations include:

 - does not check for cycles
 - only adds blocking data to bug report pages, not index pages

I've tested this lightly, and I doubt that any coding bugs will express
themselves outside of, at worst, bad data in the new fields, so I hope
this will an easy patch to accept.

-- 
see shy jo
Index: cgi/bugreport.cgi
===================================================================
RCS file: /cvs/debbugs/source/cgi/bugreport.cgi,v
retrieving revision 1.65
diff -u -r1.65 bugreport.cgi
--- cgi/bugreport.cgi   1 Jun 2004 00:41:26 -0000       1.65
+++ cgi/bugreport.cgi   16 Mar 2005 02:12:25 -0000
@@ -196,6 +196,24 @@
                . "</strong>"
                        if length($status{tags});
 
+my @blockedby= split(/ /, $status{blockedby});
+if (@blockedby && $status{"pending"} ne 'fixed' && ! length($status{done})) {
+       for my $b (@blockedby) {
+               my %s = %{getbugstatus($b)};
+               next if $s{"pending"} eq 'fixed' || length $s{done};
+               push @descstates, "fix blocked by <a href=\"" . bugurl($b) . 
"\">#$b</a>: ".htmlsanit($s{subject});
+       }
+}
+
+my @blocks= split(/ /, $status{blocks});
+if (@blocks && $status{"pending"} ne 'fixed' && ! length($status{done})) {
+       for my $b (@blocks) {
+               my %s = %{getbugstatus($b)};
+               next if $s{"pending"} eq 'fixed' || length $s{done};
+               push @descstates, "blocking fix for <a href=\"" . bugurl($b) . 
"\">#$b</a>: ".htmlsanit($s{subject});
+       }
+}
+
 my @merged= split(/ /,$status{mergedwith});
 if (@merged) {
        my $descmerged = 'merged with ';
Index: html/server-control.html.in
===================================================================
RCS file: /cvs/debbugs/source/html/server-control.html.in,v
retrieving revision 1.14
diff -u -r1.14 server-control.html.in
--- html/server-control.html.in 11 Jun 2004 16:45:45 -0000      1.14
+++ html/server-control.html.in 16 Mar 2005 02:12:26 -0000
@@ -219,6 +219,20 @@
   <p>For <a href="Developer.html#tags">their meanings</a> please consult the
   general developers' documentation for the $gBug system.
 
+<dt><code>blocks</code> <var>bugnumber</var> [ <code>+</code> | <code>-</code> 
| <code>=</code> ] <var>bug</var> [ <var>bug</var> ... ]
+
+  <dd>Use to note that one bug blocks another bug from being fixed.
+  The first listed bug is the blocker, and it is followed by the bug or bugs
+  that it blocks. Like the tags command, the list of bugs can be preceded by
+  <code>+</code>, <code>-</code>, or <code>=</code> to add, remove, or set
+  afresh the list of blocked bugs. The default is adding.
+  
+  <p>Example usage:</p>
+
+  <pre>
+       # indicates that 7890 cannot be fixed until 123456 is fixed
+       blocks 123456 7890
+  </pre>
 <dt><code>close</code> <var>bugnumber</var> (deprecated)
 
   <dd>Close $gBug report #<var>bugnumber</var>.
Index: html/server-refcard.html.in
===================================================================
RCS file: /cvs/debbugs/source/html/server-refcard.html.in,v
retrieving revision 1.5
diff -u -r1.5 server-refcard.html.in
--- html/server-refcard.html.in 12 Sep 2003 22:27:19 -0000      1.5
+++ html/server-refcard.html.in 16 Mar 2005 02:12:26 -0000
@@ -70,6 +70,8 @@
   <li><code>retitle</code> <var>bugnumber</var> <var>new-title</var>
   <li><code>merge</code> <var>bugnumber</var> <var>bugnumber</var> ...
   <li><code>unmerge</code> <var>bugnumber</var>
+  <li><code>tags</code> <var>bugnumber</var> [+-=] <var>tag</var> ...
+  <li><code>blocks</code> <var>bugnumber</var> [+-=] <var>bugnumber</var> ...
 </ul>
 
 <p><code>reopen</code> with <code>=</code> or no originator address leaves
Index: scripts/errorlib.in
===================================================================
RCS file: /cvs/debbugs/source/scripts/errorlib.in,v
retrieving revision 1.41
diff -u -r1.41 errorlib.in
--- scripts/errorlib.in 15 Feb 2004 16:12:00 -0000      1.41
+++ scripts/errorlib.in 16 Mar 2005 02:12:26 -0000
@@ -84,6 +84,8 @@
               mergedwith => 'merged-with',
               severity => 'severity',
               owner => 'owner',
+             blocks => 'blocks',
+             blockedby => 'blocked-by',
              );
 
 sub readbug {
Index: scripts/service.in
===================================================================
RCS file: /cvs/debbugs/source/scripts/service.in,v
retrieving revision 1.98
diff -u -r1.98 service.in
--- scripts/service.in  15 Mar 2005 21:40:41 -0000      1.98
+++ scripts/service.in  16 Mar 2005 02:12:28 -0000
@@ -491,6 +491,100 @@
                $data->{keywords} =~ s/\s*$//;
             } while (&getnextbug);
        }
+    } elsif (m/^blocks?\s+\#?(-?\d+)\s+(([=+-])\s*)?(\S.*)?$/i) {
+       $ok++;
+       my $bugnum = $1; $addsubcode = $3; $blocks = $4;
+       $addsub = "add";
+       if (defined $addsubcode) {
+           $addsub = "sub" if ($addsubcode eq "-");
+           $addsub = "add" if ($addsubcode eq "+");
+           $addsub = "set" if ($addsubcode eq "=");
+       }
+       
+       my @okayblocks;
+       my @badblocks;
+       foreach my $b (split /[\s,]+/, $blocks) {
+           $b=~s/^\#//;
+           if ($b=~/[0-9]+/) {
+               $ref=$b;
+               if (&getbug) {
+                   push @okayblocks, $b;
+                   &cancelbug; # done checking the bug exists
+               }
+               else {
+                   &notfoundbug;
+                    push @badblcoks, $b;
+               }
+           }
+           else {
+                push @badblcoks, $b;
+           }
+       }
+       if (@badblocks) {
+            &transcript("Unknown blocked bug/s: ".join(', ', @badbugs).".\n");
+       }
+       
+       $ref=$bugnum;
+       if (&setbug) {
+           if ($data->{blocks} eq '') {
+               &transcript("Was not blocking any bugs.\n");
+           } else {
+               &transcript("Was blocking: $data->{blocks}\n");
+           }
+           if ($addsub eq "set") {
+               $action= "Blocked bugs set to: " . join(", ", @okayblocks);
+           } elsif ($addsub eq "add") {
+               $action= "Blocked bugs added: " . join(", ", @okayblocks);
+           } elsif ($addsub eq "sub") {
+               $action= "Blocked bugs removed: " . join(", ", @okayblocks);
+           }
+           my %removedblocks;
+           my %addedblocks;
+           do {
+                &addmaintainers($data);
+               my @oldblocklist = split ' ', $data->{blocks};
+               $data->{blocks} = '' if ($addsub eq "set");
+               foreach my $b (@okayblocks) {
+                   $data->{blocks} = join ' ', grep $_ ne $b, 
+                       split ' ', $data->{blocks};
+                   $data->{blocks} = "$b $data->{blocks}" unless $addsub eq 
"sub";
+               }
+               $data->{blocks} =~ s/\s*$//;
+
+               foreach my $b (@oldblocklist) {
+                       if (! grep { $_ eq $b } split ' ', $data->{blocks}) {
+                               push @{$removedblocks{$b}}, $ref;
+                       }
+               }
+               foreach my $b (split ' ', $data->{blocks}) {
+                       if (! grep { $_ eq $b } @oldblocklist) {
+                               push @{$addedblocks{$b}}, $ref;
+                       }
+               }
+            } while (&getnextbug);
+
+           # Now that the blocks data is updated, change blocked-by data
+           # to match the changes.
+           foreach $ref (keys %addedblocks) {
+               if (&getbug) {
+                   foreach my $b (@{$addedblocks{$ref}}) {
+                       $data->{blockedby} = join ' ', grep $_ ne $b,
+                           split ' ', $data->{blockedby};
+                       $data->{blockedby} = "$b $data->{blockedby}";
+                   }
+                   &savebug;
+                }
+           }
+           foreach $ref (keys %removedblocks) {
+               if (&getbug) {
+                   foreach my $b (@{$addedblocks{$ref}}) {
+                       $data->{blockedby} = join ' ', grep $_ ne $b,
+                           split ' ', $data->{blockedby};
+                   }
+                   &savebug;
+                }
+           }
+       }
     } elsif (m/^retitle\s+\#?(-?\d+)\s+(\S.*\S)\s*$/i) {
         $ok++;
         $ref= $1; $newtitle= $2;
@@ -551,6 +645,8 @@
            &checkmatch('forwarded addr','m_forwarded',$data->{forwarded});
            $data->{severity} = '$gDefaultSeverity' if $data->{severity} eq '';
            &checkmatch('severity','m_severity',$data->{severity});
+           &checkmatch('blocks','m_blocks',$data->{blocks});
+           &checkmatch('blocked-by','m_blocked-by',$data->{blockedby});
            &checkmatch('done mark','m_done',length($data->{done}) ? 'done' : 
'open');
            &checkmatch('owner','m_owner',$data->{owner});
            foreach my $t (split /\s+/, $data->{keywords}) { $tags{$t} = 1; }

Attachment: signature.asc
Description: Digital signature

Reply via email to