+=head2 affects
+
+ eval {
+ affects(bug => $ref,
+ transcript => $transcript,
+ ($dl > 0 ? (debug => $transcript):()),
+ requester => $header{from},
+ request_addr => $controlrequestaddr,
+ message => \@log,
+ affected_packages => \%affected_packages,
+ recipients => \%recipients,
+ packages => undef,
+ add => 1,
+ remove => 0,
+ );
+ };
+ if ($@) {
+ $errors++;
+ print {$transcript} "Failed to mark $ref as affecting $packages: $@";
+ }
+
+This marks a bug as affecting packages which the bug is not actually
+in. This should only be used in cases where fixing the bug instantly
+resolves the problem in the other packages.
+
+By default, the packages are set to the list of packages passed.
+However, if you pass add => 1 or remove => 1, the list of packages
+passed are added or removed from the affects list, respectively.
+
+=cut
+
+sub affects {
+ my %param = validate_with(params => \@_,
+ spec => {bug => {type => SCALAR,
+ regex => qr/^\d+$/,
+ },
+ # specific options here
+ packages => {type => SCALAR|ARRAYREF,
+ default => [],
+ },
+ add => {type => BOOLEAN,
+ default => 0,
+ },
+ remove => {type => BOOLEAN,
+ default => 0,
+ },
+ %common_options,
+ %append_action_options,
+ },
+ );
+ if ($param{add} and $param{remove}) {
+ croak "Asking to both add and remove affects is nonsensical";
+ }
+ our $locks = 0;
+ $locks = 0;
+ local $SIG{__DIE__} = sub {
+ if ($locks) {
+ for (1..$locks) { unfilelock(); }
+ $locks = 0;
+ }
+ };
+ my ($debug,$transcript) = __handle_debug_transcript(%param);
+ my (@data);
+ ($locks, @data) = lock_read_all_merged_bugs($param{bug});
+ __handle_affected_packages(data => \@data,%param);
+ print {$transcript} __bug_info(@data);
+ add_recipients(data => \@data,
+ recipients => $param{recipients}
+ );
+ my $action = 'Did not alter affected packages';
+ for my $data (@data) {
+ print {$debug} "Going to change affects\n";
+ my @packages = splitpackages($data->{affects});
+ my %packages;
+ @packages{@packages} = (1) x @packages;
+ if ($param{add}) {
+ my @added = ();
+ for my $package (make_list($param{packages})) {
+ if (not $packages{$package}) {
+ $packages{$package} = 1;
+ push @added,$package;
+ }
+ }
+ if (@added) {
+ $action = "Added indication that $data->{bug_num} affects ".
+ english_join(', ',' and ',@added);
+ }
+ }
+ elsif ($param{remove}) {
+ my @removed = ();
+ for my $package (make_list($param{packages})) {
+ if ($packages{$package}) {
+ delete $packages{$package};
+ push @removed,$package;
+ }
+ }
+ $action = "Removed indication that $data->{bug_num} affects " .
+ english_join(', ',' and ',@removed);
+ }
+ else {
+ %packages = ();
+ for my $package (make_list($param{packages})) {
+ $packages{$package} = 1;
+ }
+ $action = "Noted that $data->{bug_num} affects ".
+ english_join(', ',' and ', keys %packages);
+ }
+ $data->{affects} = join(',',keys %packages);
+ 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";
+ add_recipients(data => $data,
+ recipients => $param{recipients},
+ );
+ }
+ if ($locks) {
+ for (1..$locks) { unfilelock(); }
+ }
+
+}
+
+