X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Fservice;h=eb10acd031a8d15755de92fba2492a899b144937;hb=443472028485f30c0ba63d0680df6e62d29cb5aa;hp=231ae83d36d411fde7eb53ea882d09d68ce991dc;hpb=cf62faa902c8716a79dcc75d4e185b987e5fa066;p=debbugs.git diff --git a/scripts/service b/scripts/service index 231ae83..eb10acd 100755 --- a/scripts/service +++ b/scripts/service @@ -122,19 +122,23 @@ print {$transcript} "Processing commands for $controlrequestaddr:\n\n"; my $dl = 0; my %affected_packages; my %recipients; +# this is the hashref which is passed to all control calls +my %limit = (); + my @common_control_options = - (($dl > 0 (debug => $transcript):()), - transcript => $transcript, + (transcript => $transcript, requester => $header{from}, request_addr => $controlrequestaddr, request_msgid => $header{'message-id'}, request_subject => $header{subject}, request_nn => $nn, - request_replyto => $replyto + request_replyto => $replyto, message => \@log, + affected_bugs => \%bug_affected, affected_packages => \%affected_packages, recipients => \%recipients, + limit => \%limit, ); my $state= 'idle'; @@ -177,10 +181,6 @@ our $mismatch; our $action; -# recipients of mail -my %recipients; -# affected_packages -my %affected_packages; my $ok = 0; my $unknowns = 0; my $procline=0; @@ -204,12 +204,15 @@ for ($procline=0; $procline<=$#bodylines; $procline++) { print {$transcript} "> $_\n"; next if m/^\s*\#/; $action= ''; - if (m/^stop\s*$/i || m/^quit\s*$/i || m/^--\s*$/ || m/^thank(?:s|\s*you)?\s*$/i || m/^kthxbye\s*$/i) { + if (m/^(?:stop|quit|--|thank(?:s|\s*you)?|kthxbye)\.*\s*$/i) { print {$transcript} "Stopping processing here.\n\n"; last; } elsif (m/^debug\s+(\d+)$/i && $1 >= 0 && $1 <= 1000) { $dl= $1+0; - print {$transcript} "Debug level $dl.\n\n"; + if ($dl > 0 and not grep /debug/,@common_control_options) { + push @common_control_options,(debug => $transcript); + } + print {$transcript} "Debug level $dl.\n\n"; } elsif (m/^(send|get)\s+\#?(\d{2,})$/i) { $ref= $2+0; &sendlynxdoc("bugreport.cgi?bug=$ref","logs for $gBug#$ref"); @@ -463,69 +466,35 @@ END } #### "developer only" ones start here } elsif (m/^close\s+\#?(-?\d+)(?:\s+(\d.*))?$/i) { - $ok++; - $ref= $1; + $ok++; + $ref= $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref}=1; - my $version= $2; - if (&setbug) { - print {$transcript} "'close' is deprecated; see http://$gWebDomain/Developer$gHTMLSuffix#closing.\n"; - if (length($data->{done}) and not defined($version)) { - print {$transcript} "$gBug is already closed, cannot re-close.\n\n"; - &nochangebug; - } else { - $action= "$gBug " . - (defined($version) ? - "marked as fixed in version $version" : - "closed") . - ", send any further explanations to $data->{originator}"; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - actions_taken => {done => 1}, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{done}= $replyto; - my @keywords= split ' ', $data->{keywords}; - my $extramessage = ''; - if (grep $_ eq 'pending', @keywords) { - $extramessage= "Removed pending tag.\n"; - $data->{keywords}= join ' ', grep $_ ne 'pending', - @keywords; - } - addfixedversions($data, $data->{package}, $version, 'binary'); - - my $message= <{originator} -Subject: $gBug#$ref acknowledged by developer - ($header{'subject'}) -References: $header{'message-id'} $data->{msgid} -In-Reply-To: $data->{msgid} -Message-ID: -Reply-To: $ref\@$gEmailDomain -X-$gProject-PR-Message: they-closed-control $ref - -This is an automatic notification regarding your $gBug report -#$ref: $data->{subject}, -which was filed against the $data->{package} package. - -It has been marked as closed by one of the developers, namely -$replyto. - -You should be hearing from them with a substantive response shortly, -in case you haven't already. If not, please contact them directly. - -$gMaintainer -(administrator, $gProject $gBugs database) - -END - &sendmailmessage($message,$data->{originator}); - } while (&getnextbug); - } - } + if (defined $2) { + eval { + set_fixed(@common_control_options, + bug => $ref, + fixed => $2, + add => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to add fixed version '$2' to $ref: ".cleanup_eval_fail($@,$debug)."\n"; + } + } + eval { + set_done(@common_control_options, + done => 1, + bug => $ref, + reopen => 0, + notify_submitter => 1, + clear_fixed => 0, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to mark $ref as done: ".cleanup_eval_fail($@,$debug)."\n"; + } } elsif (m/^reassign\s+\#?(-?\d+)\s+ # bug and command (?:(?:((?:src:|source:)?$config{package_name_re}) # new package (?:\s+((?:$config{package_name_re}\/)? @@ -544,7 +513,6 @@ END } @new_packages = map {y/A-Z/a-z/; s/^(?:src|source):/src:/; $_;} @new_packages; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref}=1; my $version= $3; eval { set_package(@common_control_options, @@ -555,19 +523,19 @@ END # to set_found if (defined($version) && length $version) { set_found(@common_control_options, - bug => $ref, - version => $version, + bug => $ref, + found => $version, ); } }; if ($@) { $errors++; - print {$transcript} "Failed to clear fixed versions and reopen on $ref: $@"; + print {$transcript} "Failed to clear fixed versions and reopen on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^reopen\s+\#?(-?\d+)(?:\s+([\=\!]|(?:\S.*\S)))?$/i) { $ok++; $ref= $1; - $bug_affected{$ref}=1; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; my $new_submitter = $2; if (defined $new_submitter) { if ($new_submitter eq '=') { @@ -578,14 +546,15 @@ END } } eval { - reopen(@common_control_options, - bug => $ref, - submitter => $new_submitter, - ); + set_done(@common_control_options, + bug => $ref, + reopen => 1, + submitter => $new_submitter, + ); }; if ($@) { $errors++; - print {$transcript} "Failed to reopen $ref: $@"; + print {$transcript} "Failed to reopen $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m{^(?:(?i)found)\s+\#?(-?\d+) (?:\s+((?:$config{package_name_re}\/)? @@ -609,7 +578,7 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to add found on $ref: $@"; + print {$transcript} "Failed to add found on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } else { @@ -622,7 +591,7 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to clear fixed versions and reopen on $ref: $@"; + print {$transcript} "Failed to clear fixed versions and reopen on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } } @@ -647,7 +616,7 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to remove found on $ref: $@"; + print {$transcript} "Failed to remove found on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m{^(?:(?i)fixed)\s+\#?(-?\d+) @@ -671,7 +640,7 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to add fixed on $ref: $@"; + print {$transcript} "Failed to add fixed on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m{^(?:(?i)notfixed)\s+\#?(-?\d+) @@ -695,13 +664,12 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to remove fixed on $ref: $@"; + print {$transcript} "Failed to remove fixed on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^submitter\s+\#?(-?\d+)\s+(\!|\S.*\S)$/i) { $ok++; $ref= $1; - $bug_affected{$ref}=1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; my $newsubmitter = $2 eq '!' ? $replyto : $2; if (not Mail::RFC822::Address::valid($newsubmitter)) { @@ -717,7 +685,7 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to set submitter on $ref: $@"; + print {$transcript} "Failed to set submitter on $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } } elsif (m/^forwarded\s+\#?(-?\d+)\s+(\S.*\S)$/i) { @@ -725,7 +693,6 @@ END $ref= $1; my $forward_to= $2; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { set_forwarded(@common_control_options, bug => $ref, @@ -734,13 +701,12 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to set the forwarded-to-address of $ref: $@"; + print {$transcript} "Failed to set the forwarded-to-address of $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^notforwarded\s+\#?(-?\d+)$/i) { $ok++; $ref= $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { set_forwarded(@common_control_options, bug => $ref, @@ -749,13 +715,12 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to clear the forwarded-to-address of $ref: $@"; + print {$transcript} "Failed to clear the forwarded-to-address of $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^(?:severity|priority)\s+\#?(-?\d+)\s+([-0-9a-z]+)$/i) { $ok++; $ref= $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref}=1; my $newseverity= $2; if (exists $gObsoleteSeverities{$newseverity}) { print {$transcript} "Severity level \`$newseverity' is obsolete. " . @@ -775,31 +740,52 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to set severity of $config{bug} $ref to $newseverity: $@"; + print {$transcript} "Failed to set severity of $config{bug} $ref to $newseverity: ".cleanup_eval_fail($@,$debug)."\n"; } } - } elsif (m/^tags?\s+\#?(-?\d+)\s+(([=+-])\s*)?(\S.*)?$/i) { - ### TODO: [#505189] Consider altering this to accept tag #nnn + foo - bar - baz + } elsif (m/^tags?\s+\#?(-?\d+)\s+(\S.*)$/i) { $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref}=1; - my $addsubcode = $3; - my @add_remove_option = (); - if (defined $addsubcode) { - if ($addsubcode eq '-') { - push @add_remove_option,(remove => 1); - } - elsif ($addsubcode eq '+') { - push @add_remove_option,(add => 1); + my $tags = $2; + my @tags = map {m/^([+=-])(.+)/ ? ($1,$2):($_)} split /[\s,]+/, $tags; + # this is an array of hashrefs which contain two elements, the + # first of which is the array of tags, the second is the + # option to pass to set_tag (we use a hashref here to make it + # more obvious what is happening) + my @tag_operations; + my @badtags; + for my $tag (@tags) { + if ($tag =~ /^[=+-]$/) { + if ($tag eq '=') { + @tag_operations = {tags => [], + option => [], + }; + } + elsif ($tag eq '-') { + push @tag_operations, + {tags => [], + option => [remove => 1], + }; + } + elsif ($tag eq '+') { + push @tag_operations, + {tags => [], + option => [add => 1], + }; + } + next; } - } - my $tags = $4; - my @tags = /[\s,]+/, $tags; - foreach my $tag (@tags) { if (not defined first {$_ eq $tag} @{$config{tags}}) { - push @badtags, $t; + push @badtags, $tag; + next; + } + if (not @tag_operations) { + @tag_operations = {tags => [], + option => [add => 1], + }; } + push @{$tag_operations[-1]{tags}},$tag; } if (@badtags) { print {$transcript} "Unknown tag/s: ".join(', ', @badtags).".\n". @@ -807,308 +793,98 @@ END $errors++; } eval { - set_tags(@common_control_options, - bug => $ref, - tags => [@tags], - warn_on_bad_tags => 0, # don't warn on bad tags, - # 'cause we do that above - @add_remove_option, - ); + for my $operation (@tag_operations) { + set_tag(@common_control_options, + bug => $ref, + tag => [@{$operation->{tags}}], + warn_on_bad_tags => 0, # don't warn on bad tags, + # 'cause we do that above + @{$operation->{option}}, + ); + } }; if ($@) { # we intentionally have two errors here if there is a bad # tag and the above fails for some reason $errors++; - print {$transcript} "Failed to alter tags of $config{bug} $ref: $@"; + print {$transcript} "Failed to alter tags of $config{bug} $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - } elsif (m/^(un)?block\s+\#?(-?\d+)\s+(by|with)\s+(\S.*)?$/i) { + } elsif (m/^(un)?block\s+\#?(-?\d+)\s+(?:by|with)\s+(\S.*)?$/i) { $ok++; - my $bugnum = $2; my $blockers = $4; - my $addsub = "add"; - $addsub = "sub" if (defined $1 and $1 eq "un"); - if ($bugnum =~ m/^-\d+$/ && defined $clonebugs{$bugnum}) { - $bugnum = $clonebugs{$bugnum}; - } - - my @okayblockers; - my @badblockers; - foreach my $b (split /[\s,]+/, $blockers) { - $b=~s/^\#//; - if ($b=~/[0-9]+/) { - $ref=$b; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - if (&getbug) { - &foundbug; - push @okayblockers, $ref; - - # add to the list all bugs that are merged with $b, - # because all of their data must be kept in sync - my @thisbugmergelist= split(/ /,$data->{mergedwith}); - &cancelbug; - - foreach $ref (@thisbugmergelist) { - if (&getbug) { - push @okayblockers, $ref; - &cancelbug; - } - } - } - else { - ¬foundbug; - push @badblockers, $ref; - } - } - else { - push @badblockers, $b; - } - } - if (@badblockers) { - print {$transcript} "Unknown blocking bug/s: ".join(', ', @badblockers).".\n"; + $ref= $2; + my $add_remove = defined $1 && $1 eq 'un'; + my @blockers = map {exists $clonebugs{$_}?$clonebugs{$_}:$_} split /[\s,]+/, $3; + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_blocks(@common_control_options, + bug => $ref, + block => \@blockers, + $add_remove ? (remove => 1):(add => 1), + ); + }; + if ($@) { $errors++; - } - - $ref=$bugnum; - if (&setbug) { - if ($data->{blockedby} eq '') { - print {$transcript} "Was not blocked by any bugs.\n"; - } else { - print {$transcript} "Was blocked by: $data->{blockedby}\n"; - } - if ($addsub eq "set") { - $action= "Blocking bugs of $bugnum set to: " . join(", ", @okayblockers); - } elsif ($addsub eq "add") { - $action= "Blocking bugs of $bugnum added: " . join(", ", @okayblockers); - } elsif ($addsub eq "sub") { - $action= "Blocking bugs of $bugnum removed: " . join(", ", @okayblockers); - } - my %removedblocks; - my %addedblocks; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - my @oldblockerlist = split ' ', $data->{blockedby}; - $data->{blockedby} = '' if ($addsub eq "set"); - foreach my $b (@okayblockers) { - $data->{blockedby} = manipset($data->{blockedby}, $b, - ($addsub ne "sub")); - } - - foreach my $b (@oldblockerlist) { - if (! grep { $_ eq $b } split ' ', $data->{blockedby}) { - push @{$removedblocks{$b}}, $ref; - } - } - foreach my $b (split ' ', $data->{blockedby}) { - if (! grep { $_ eq $b } @oldblockerlist) { - push @{$addedblocks{$b}}, $ref; - } - } - } while (&getnextbug); - - # Now that the blockedby data is updated, change blocks data - # to match the changes. - foreach $ref (keys %addedblocks) { - if (&getbug) { - foreach my $b (@{$addedblocks{$ref}}) { - $data->{blocks} = manipset($data->{blocks}, $b, 1); - } - &savebug; - } - } - foreach $ref (keys %removedblocks) { - if (&getbug) { - foreach my $b (@{$removedblocks{$ref}}) { - $data->{blocks} = manipset($data->{blocks}, $b, 0); - } - &savebug; - } - } + print {$transcript} "Failed to set blocking bugs of $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^retitle\s+\#?(-?\d+)\s+(\S.*\S)\s*$/i) { $ok++; $ref= $1; my $newtitle= $2; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { - set_title(bug => $ref, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - requester => $header{from}, - request_addr => $controlrequestaddr, - message => \@log, - recipients => \%recipients, + set_title(@common_control_options, + bug => $ref, title => $newtitle, ); }; if ($@) { $errors++; - print {$transcript} "Failed to set the title of $ref: $@"; + print {$transcript} "Failed to set the title of $ref: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^unmerge\s+\#?(-?\d+)$/i) { $ok++; $ref= $1; - $bug_affected{$ref} = 1; - if (&setbug) { - if (!length($data->{mergedwith})) { - print {$transcript} "$gBug is not marked as being merged with any others.\n\n"; - &nochangebug; - } else { - $mergelowstate eq 'locked' || die "$mergelowstate ?"; - $action= "Disconnected #$ref from all other report(s)."; - my @newmergelist= split(/ /,$data->{mergedwith}); - my $discref= $ref; - @bug_affected{@newmergelist} = 1 x @newmergelist; - do { - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - $data->{mergedwith}= ($ref == $discref) ? '' - : join(' ',grep($_ ne $ref,@newmergelist)); - } while (&getnextbug); - } + $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; + eval { + set_merged(@common_control_options, + bug => $ref, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to unmerge $ref: $@".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^merge\s+#?(-?\d+(\s+#?-?\d+)+)\s*$/i) { $ok++; - my @tomerge= sort { $a <=> $b } split(/\s+#?/,$1); - my @newmergelist= (); - my %tags = (); - my %found = (); - my %fixed = (); - &getmerge; - while (defined($ref= shift(@tomerge))) { - print {$transcript} "D| checking merge $ref\n" if $dl; - $ref+= 0; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - next if grep($_ == $ref,@newmergelist); - if (!&getbug) { ¬foundbug; @newmergelist=(); last } - if (!&checkpkglimit) { &cancelbug; @newmergelist=(); last; } - &foundbug; - print {$transcript} "D| adding $ref ($data->{mergedwith})\n" if $dl; - $mismatch= ''; - &checkmatch('package','m_package',$data->{package},@newmergelist); - &checkmatch('forwarded addr','m_forwarded',$data->{forwarded},@newmergelist); - $data->{severity} = '$gDefaultSeverity' if $data->{severity} eq ''; - &checkmatch('severity','m_severity',$data->{severity},@newmergelist); - &checkmatch('blocks','m_blocks',$data->{blocks},@newmergelist); - &checkmatch('blocked-by','m_blockedby',$data->{blockedby},@newmergelist); - &checkmatch('done mark','m_done',length($data->{done}) ? 'done' : 'open',@newmergelist); - &checkmatch('owner','m_owner',$data->{owner},@newmergelist); - &checkmatch('summary','m_summary',$data->{summary},@newmergelist); - &checkmatch('affects','m_affects',$data->{affects},@newmergelist); - foreach my $t (split /\s+/, $data->{keywords}) { $tags{$t} = 1; } - foreach my $f (@{$data->{found_versions}}) { $found{$f} = 1; } - foreach my $f (@{$data->{fixed_versions}}) { $fixed{$f} = 1; } - if (length($mismatch)) { - print {$transcript} "Mismatch - only $gBugs in same state can be merged:\n". - $mismatch."\n"; - $errors++; - &cancelbug; @newmergelist=(); last; - } - push(@newmergelist,$ref); - push(@tomerge,split(/ /,$data->{mergedwith})); - &cancelbug; - } - if (@newmergelist) { - @newmergelist= sort { $a <=> $b } @newmergelist; - $action= "Merged @newmergelist."; - delete @fixed{keys %found}; - for $ref (@newmergelist) { - &getbug || die "huh ? $gBug $ref disappeared during merge"; - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - @bug_affected{@newmergelist} = 1 x @newmergelist; - $data->{mergedwith}= join(' ',grep($_ != $ref,@newmergelist)); - $data->{keywords}= join(' ', keys %tags); - $data->{found_versions}= [sort keys %found]; - $data->{fixed_versions}= [sort keys %fixed]; - &savebug; - } - print {$transcript} "$action\n\n"; + my @tomerge; + ($ref,@tomerge) = map {exists $clonebugs{$_}?$clonebugs{$_}:$_} + split(/\s+#?/,$1); + eval { + set_merged(@common_control_options, + bug => $ref, + merge_with => \@tomerge, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to merge $ref: $@".cleanup_eval_fail($@,$debug)."\n"; } - &endmerge; } elsif (m/^forcemerge\s+\#?(-?\d+(?:\s+\#?-?\d+)+)\s*$/i) { $ok++; - my @temp = split /\s+\#?/,$1; - my $master_bug = shift @temp; - my $master_bug_data; - my @tomerge = sort { $a <=> $b } @temp; - unshift @tomerge,$master_bug; - print {$transcript} "D| force merging ".join(',',@tomerge)."\n" if $dl; - my @newmergelist= (); - my %tags = (); - my %found = (); - my %fixed = (); - # Here we try to do the right thing. - # First, if the bugs are in the same package, we merge all of the found, fixed, and tags. - # If not, we discard the found and fixed. - # Everything else we set to the values of the first bug. - &getmerge; - while (defined($ref= shift(@tomerge))) { - print {$transcript} "D| checking merge $ref\n" if $dl; - $ref+= 0; - if ($ref =~ m/^-\d+$/ && defined $clonebugs{$ref}) { - $ref = $clonebugs{$ref}; - } - next if grep($_ == $ref,@newmergelist); - if (!&getbug) { ¬foundbug; @newmergelist=(); last } - if (!&checkpkglimit) { &cancelbug; @newmergelist=(); last; } - &foundbug; - print {$transcript} "D| adding $ref ($data->{mergedwith})\n" if $dl; - $master_bug_data = $data if not defined $master_bug_data; - if ($data->{package} ne $master_bug_data->{package}) { - print {$transcript} "Mismatch - only $gBugs in the same package can be forcibly merged:\n". - "$gBug $ref is not in the same package as $master_bug\n"; - $errors++; - &cancelbug; @newmergelist=(); last; - } - for my $t (split /\s+/,$data->{keywords}) { - $tags{$t} = 1; - } - @found{@{$data->{found_versions}}} = (1) x @{$data->{found_versions}}; - @fixed{@{$data->{fixed_versions}}} = (1) x @{$data->{fixed_versions}}; - push(@newmergelist,$ref); - push(@tomerge,split(/ /,$data->{mergedwith})); - &cancelbug; - } - if (@newmergelist) { - @newmergelist= sort { $a <=> $b } @newmergelist; - $action= "Forcibly Merged @newmergelist."; - delete @fixed{keys %found}; - for $ref (@newmergelist) { - &getbug || die "huh ? $gBug $ref disappeared during merge"; - $affected_packages{$data->{package}} = 1; - add_recipients(data => $data, - recipients => \%recipients, - transcript => $transcript, - ($dl > 0 ? (debug => $transcript):()), - ); - @bug_affected{@newmergelist} = 1 x @newmergelist; - $data->{mergedwith}= join(' ',grep($_ != $ref,@newmergelist)); - $data->{keywords}= join(' ', keys %tags); - $data->{found_versions}= [sort keys %found]; - $data->{fixed_versions}= [sort keys %fixed]; - my @field_list = qw(forwarded package severity blocks blockedby owner done affects summary); - @{$data}{@field_list} = @{$master_bug_data}{@field_list}; - &savebug; - } - print {$transcript} "$action\n\n"; + my @tomerge; + ($ref,@tomerge) = map {exists $clonebugs{$_}?$clonebugs{$_}:$_} + split(/\s+#?/,$1); + eval { + set_merged(@common_control_options, + bug => $ref, + merge_with => \@tomerge, + force => 1, + masterbug => 1, + ); + }; + if ($@) { + $errors++; + print {$transcript} "Failed to forcibly merge $ref: ".cleanup_eval_fail($@,$debug)."\n"; } - &endmerge; } elsif (m/^clone\s+#?(\d+)\s+((-\d+\s+)*-\d+)\s*$/i) { $ok++; @@ -1117,73 +893,65 @@ 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=; $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++; my @pkgs = split /\s+/, $1; if (scalar(@pkgs) > 0) { %limit_pkgs = map { ($_, 1) } @pkgs; - print {$transcript} "Ignoring bugs not assigned to: " . - join(" ", keys(%limit_pkgs)) . "\n\n"; + $limit{package} = [@pkgs]; + print {$transcript} "Limiting to bugs with field 'package' containing at least one of ".join(', ',map {qq('$_')} @pkgs)."\n"; + print {$transcript} "Limit currently set to"; + for my $limit_field (keys %limit) { + print {$transcript} " '$limit_field':".join(', ',map {qq('$_')} @{$limit{$limit_field}})."\n"; + } + print {$transcript} "\n"; } else { - %limit_pkgs = (); - print {$transcript} "Not ignoring any bugs.\n\n"; + %limit_pkgs = (); + $limit{package} = []; + print {$transcript} "Limit cleared.\n\n"; + } + } elsif (m/^limit\:?\s+(\S.*\S)\s*$/) { + $ok++; + my ($field,@options) = split /\s+/, $1; + $field = lc($field); + if ($field =~ /^(?:clear|unset|blank)$/) { + %limit = (); + print {$transcript} "Limit cleared.\n\n"; + } + elsif (exists $Debbugs::Status::fields{$field} or $field eq 'source') { + # %limit can actually contain regexes, but because they're + # not evaluated in Safe, DO NOT allow them through without + # fixing this. + $limit{$field} = [@options]; + print {$transcript} "Limiting to bugs with field '$field' containing at least one of ".join(', ',map {qq('$_')} @options)."\n"; + print {$transcript} "Limit currently set to"; + for my $limit_field (keys %limit) { + print {$transcript} " '$limit_field':".join(', ',map {qq('$_')} @{$limit{$limit_field}})."\n"; + } + print {$transcript} "\n"; + } + else { + print {$transcript} "Limit key $field not understood. Stopping processing here.\n\n"; + $errors++; + last; } } elsif (m/^affects?\s+\#?(-?\d+)(?:\s+((?:[=+-])?)\s*(\S.*)?)?\s*$/i) { $ok++; @@ -1191,17 +959,17 @@ END my $add_remove = $2 || ''; my $packages = $3 || ''; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { affects(@common_control_options, - packages => [splitpackages($3)], + bug => $ref, + package => [splitpackages($3)], ($add_remove eq '+'?(add => 1):()), ($add_remove eq '-'?(remove => 1):()), ); }; if ($@) { $errors++; - print {$transcript} "Failed to mark $ref as affecting package(s): $@"; + print {$transcript} "Failed to mark $ref as affecting package(s): ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^summary\s+\#?(-?\d+)\s*(\d+|)\s*$/i) { @@ -1209,7 +977,6 @@ END $ref = $1; my $summary_msg = length($2)?$2:undef; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { summary(@common_control_options, bug => $ref, @@ -1218,7 +985,7 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to give $ref a summary: $@"; + print {$transcript} "Failed to give $ref a summary: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^owner\s+\#?(-?\d+)\s+((?:\S.*\S)|\!)\s*$/i) { @@ -1229,7 +996,6 @@ END if ($newowner eq '!') { $newowner = $replyto; } - $bug_affected{$ref} = 1; eval { owner(@common_control_options, bug => $ref, @@ -1238,13 +1004,12 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to mark $ref as having an owner: $@"; + print {$transcript} "Failed to mark $ref as having an owner: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^noowner\s+\#?(-?\d+)\s*$/i) { $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { owner(@common_control_options, bug => $ref, @@ -1253,13 +1018,12 @@ END }; if ($@) { $errors++; - print {$transcript} "Failed to mark $ref as not having an owner: $@"; + print {$transcript} "Failed to mark $ref as not having an owner: ".cleanup_eval_fail($@,$debug)."\n"; } } elsif (m/^unarchive\s+#?(\d+)$/i) { $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { bug_unarchive(@common_control_options, bug => $ref, @@ -1273,7 +1037,6 @@ END $ok++; $ref = $1; $ref = $clonebugs{$ref} if exists $clonebugs{$ref}; - $bug_affected{$ref} = 1; eval { bug_archive(@common_control_options, bug => $ref, @@ -1338,13 +1101,12 @@ References: $header{'message-id'} Message-ID: Precedence: bulk ${packagepr}X-$gProject-PR-Message: transcript - -${transcript_scalar}Please contact me if you need assistance. - -$gMaintainer -(administrator, $gProject $gBugs database) END +$reply .= fill_template('mail/message_body', + {body => "${transcript_scalar}Please contact me if you need assistance."}, + ); + my $repliedshow= join(', ',$replyto, determine_recipients(recipients => \%recipients, cc => 1, @@ -1391,12 +1153,15 @@ sub fill_template{ my $variables = {config => \%config, defined($ref)?(ref => $ref):(), defined($data)?(data => $data):(), + refs => [map {exists $clonebugs{$_}?$clonebugs{$_}:$_} keys %bug_affected], %{$extra_var}, }; my $hole_var = {'&bugurl' => sub{"$_[0]: ". 'http://'.$config{cgi_domain}.'/'. - Debbugs::CGI::bug_url($_[0]); + Debbugs::CGI::bug_links(bug=>$_[0], + links_only => 1, + ); } }; return fill_in_template(template => $template,