]> git.donarmstrong.com Git - debbugs.git/commitdiff
abstract out bug cloning
authorDon Armstrong <don@donarmstrong.com>
Tue, 13 Mar 2012 05:30:23 +0000 (22:30 -0700)
committerDon Armstrong <don@donarmstrong.com>
Tue, 13 Mar 2012 05:30:23 +0000 (22:30 -0700)
Debbugs/Control.pm
scripts/service

index cec80f9b78ec648eac7a64f44b1133f852be13cd..78efdf12e512f0c940222508c5163e0990fe8370 100644 (file)
@@ -96,6 +96,7 @@ BEGIN{
                     block   => [qw(set_blocks)],
                     merge   => [qw(set_merged)],
                     tag     => [qw(set_tag)],
+                    clone   => [qw(clone_bug)],
                     archive => [qw(bug_archive bug_unarchive),
                                ],
                     log     => [qw(append_action_to_log),
@@ -108,7 +109,7 @@ BEGIN{
 
 use Debbugs::Config qw(:config);
 use Debbugs::Common qw(:lock buglog :misc get_hashname sort_versions);
-use Debbugs::Status qw(bug_archiveable :read :hook writebug splitpackages split_status_fields get_bug_status);
+use Debbugs::Status qw(bug_archiveable :read :hook writebug new_bug splitpackages split_status_fields get_bug_status);
 use Debbugs::CGI qw(html_escape);
 use Debbugs::Log qw(:misc :write);
 use Debbugs::Recipients qw(:add);
@@ -117,6 +118,7 @@ use Debbugs::Packages qw(:versions :mapping);
 use Data::Dumper qw();
 use Params::Validate qw(validate_with :types);
 use File::Path qw(mkpath);
+use File::Copy qw(copy);
 use IO::File;
 
 use Debbugs::Text qw(:templates);
@@ -2756,6 +2758,138 @@ sub summary {
 
 
 
+=head2 clone_bug
+
+     eval {
+           clone_bug(bug          => $ref,
+                     transcript   => $transcript,
+                     ($dl > 0 ? (debug => $transcript):()),
+                     requester    => $header{from},
+                     request_addr => $controlrequestaddr,
+                     message      => \@log,
+                      affected_packages => \%affected_packages,
+                     recipients   => \%recipients,
+                    );
+       };
+       if ($@) {
+           $errors++;
+           print {$transcript} "Failed to clone bug $ref bar: $@";
+       }
+
+Clones the given bug.
+
+We currently don't support cloning merged bugs, but this could be
+handled by internally unmerging, cloning, then remerging the bugs.
+
+=cut
+
+sub clone_bug {
+    my %param = validate_with(params => \@_,
+                             spec   => {bug => {type   => SCALAR,
+                                                regex  => qr/^\d+$/,
+                                               },
+                                        new_bugs => {type => ARRAYREF,
+                                                    },
+                                        new_clones => {type => HASHREF,
+                                                       default => {},
+                                                      },
+                                        %common_options,
+                                        %append_action_options,
+                                       },
+                            );
+    my %info =
+       __begin_control(%param,
+                       command  => 'clone'
+                      );
+    my ($debug,$transcript) =
+       @info{qw(debug transcript)};
+    my @data = @{$info{data}};
+    my @bugs = @{$info{bugs}};
+
+    my $action = '';
+    for my $data (@data) {
+       if (length($data->{mergedwith})) {
+           die "Bug is marked as being merged with others. Use an existing clone.\n";
+       }
+    }
+    if (@data != 1) {
+       die "Not exactly one bug‽ This shouldn't happen.";
+    }
+    my $data = $data[0];
+    my %clones;
+    for my $newclone_id (@{$param{new_bugs}}) {
+       my $new_bug_num = new_bug(copy => $data->{bug_num});
+       $param{new_clones}{$newclone_id} = $new_bug_num;
+       $clones{$newclone_id} = $new_bug_num;
+    }
+    my @new_bugs = sort values %clones;
+    my @collapsed_ids;
+    for my $new_bug (@new_bugs) {
+       # no collapsed ids or the higher collapsed id is not one less
+       # than the next highest new bug
+       if (not @collapsed_ids or 
+           $collapsed_ids[-1][1]+1 != $new_bug) {
+           push @collapsed_ids,[$new_bug,$new_bug];
+       }
+       else {
+           $collapsed_ids[-1][1] = $new_bug;
+       }
+    }
+    my @collapsed;
+    for my $ci (@collapsed_ids) {
+       if ($ci->[0] == $ci->[1]) {
+           push @collapsed,$ci->[0];
+       }
+       else {
+           push @collapsed,$ci->[0].'-'.$ci->[1]
+       }
+    }
+    my $collapsed_str = english_join(\@collapsed);
+    $action = "Bug $data->{bug_num} cloned as bug".(@new_bugs > 1?'s':'').' '.$collapsed_str;
+    for my $new_bug (@new_bugs) {
+       append_action_to_log(bug => $new_bug,
+                            get_lock => 1,
+                            __return_append_to_log_options(
+                                                           %param,
+                                                           action => $action,
+                                                          ),
+                           )
+           if not exists $param{append_log} or $param{append_log};
+    }
+    append_action_to_log(bug => $data->{bug_num},
+                        get_lock => 0,
+                        __return_append_to_log_options(
+                                                       %param,
+                                                       action => $action,
+                                                      ),
+                       )
+       if not exists $param{append_log} or $param{append_log};
+    writebug($data->{bug_num},$data);
+    print {$transcript} "$action\n";
+    __end_control(%info);
+    # bugs that this bug is blocking are also blocked by the new clone(s)
+    for my $bug (split ' ', $data->{blocks}) {
+       for my $new_bug (@new_bugs) {
+           set_blocks(bug => $new_bug,
+                      blocks => $bug,
+                      hash_slice(%param,
+                                 keys %common_options,
+                                 keys %append_action_options),
+                     );
+       }
+    }
+    # bugs that this bug is blocked by are also blocking the new clone(s)
+    for my $bug (split ' ', $data->{blockedby}) {
+       for my $new_bug (@new_bugs) {
+           set_blocks(bug => $bug,
+                      blocks => $new_bug,
+                      hash_slice(%param,
+                                 keys %common_options,
+                                 keys %append_action_options),
+                     );
+       }
+    }
+}
 
 
 
@@ -2977,7 +3111,7 @@ sub bug_archive {
               print {$transcript} "archived $bug to archive/$dir (from $param{bug})\n";
          }
          unlink(map {"$config{spool_dir}/db-h/$dir/$_"} @files_to_remove);
-         print {$transcript} "deleted $bug (from $param{bug})\n";
+         print {$debug} "deleted $bug (from $param{bug})\n";
      }
      bughook_archive(@bugs);
      __end_control(%info);
index f726417a5e715e80bb2253d563fe1f83ba2085ff..eb10acd031a8d15755de92fba2492a899b144937 100755 (executable)
@@ -883,7 +883,6 @@ END
        };
        if ($@) {
            $errors++;
-           print {$transcript} $@;
            print {$transcript} "Failed to forcibly merge $ref: ".cleanup_eval_fail($@,$debug)."\n";
        }
     } elsif (m/^clone\s+#?(\d+)\s+((-\d+\s+)*-\d+)\s*$/i) {
@@ -894,62 +893,23 @@ END
        my $newbugsneeded = scalar(@newclonedids);
 
        $ref = $origref;
+       if (exists $clonebugs{$ref}) {
+           $ref = $clonebugs{$ref};
+       }
        $bug_affected{$ref} = 1;
-       if (&setbug) {
-           $affected_packages{$data->{package}} = 1;
-           if (length($data->{mergedwith})) {
-               print {$transcript} "$gBug is marked as being merged with others. Use an existing clone.\n\n";
-               $errors++;
-               &nochangebug;
-           } else {
-               &filelock("nextnumber.lock");
-               open(N,"nextnumber") || die "nextnumber: read: $!";
-               my $v=<N>; $v =~ s/\n$// || die "nextnumber bad format";
-               my $firstref= $v+0;  $v += $newbugsneeded;
-               open(NN,">nextnumber"); print NN "$v\n"; close(NN);
-               unfilelock();
-
-               my $lastref = $firstref + $newbugsneeded - 1;
-
-               if ($newbugsneeded == 1) {
-                   $action= "$gBug $origref cloned as bug $firstref.";
-               } else {
-                   $action= "$gBug $origref cloned as bugs $firstref-$lastref.";
-               }
-
-               my $blocks = $data->{blocks};
-               my $blockedby = $data->{blockedby};
-               
-               &getnextbug;
-               my $ohash = get_hashname($origref);
-               my $clone = $firstref;
-                @bug_affected{@newclonedids} = 1 x @newclonedids;
-               for my $newclonedid (@newclonedids) {
-                   $clonebugs{$newclonedid} = $clone;
-           
-                   my $hash = get_hashname($clone);
-                   copy("db-h/$ohash/$origref.log", "db-h/$hash/$clone.log");
-                   copy("db-h/$ohash/$origref.status", "db-h/$hash/$clone.status");
-                   copy("db-h/$ohash/$origref.summary", "db-h/$hash/$clone.summary");
-                   copy("db-h/$ohash/$origref.report", "db-h/$hash/$clone.report");
-                   &bughook('new', $clone, $data);
-               
-                   # Update blocking info of bugs blocked by or blocking the
-                   # cloned bug.
-                   foreach $ref (split ' ', $blocks) {
-                       &getbug;
-                       $data->{blockedby} = manipset($data->{blockedby}, $clone, 1);
-                       &savebug;
-                   }
-                   foreach $ref (split ' ', $blockedby) {
-                       &getbug;
-                       $data->{blocks} = manipset($data->{blocks}, $clone, 1);
-                       &savebug;
-                   }
-
-                   $clone++;
-               }
-           }
+       eval {
+           my %new_clones;
+           clone_bug(@common_control_options,
+                     bug => $ref,
+                     new_bugs => \@newclonedids,
+                     new_clones => \%new_clones,
+                    );
+           %clonebugs = (%clonebugs,
+                         %new_clones);
+       };
+       if ($@) {
+           $errors++;
+           print {$transcript} "Failed to clone $ref: ".cleanup_eval_fail($@,$debug)."\n";
        }
     } elsif (m/^package\:?\s+(\S.*\S)?\s*$/i) {
         $ok++;