From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 451931FA00 for ; Mon, 8 Feb 2021 09:05:22 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 04/13] lei q: support --alert=CMD for early MUA users Date: Sun, 7 Feb 2021 23:05:12 -1000 Message-Id: <20210208090521.28909-5-e@80x24.org> In-Reply-To: <20210208090521.28909-1-e@80x24.org> References: <20210208090521.28909-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: For --mua users writing to lock-free -o MFOLDER destinations; we'll keep -WINCH and send an ASCII terminal bell when results are complete. This is intended to let early MUA spawners know when lei2mail is done writing results. We'll also support running arbitrary commands. It may be used to run play(1) (from SoX), handle pipelines+redirects (e.g. "/bin/sh -c 'echo search done | wall'") or other commands. --- lib/PublicInbox/LEI.pm | 54 ++++++++++++++++++++++++---------- lib/PublicInbox/LeiOverview.pm | 5 +++- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index e95a674b..7b2a3e6f 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -112,7 +112,7 @@ our %CMD = ( # sorted in order of importance/use: save-as=s output|mfolder|o=s format|f=s dedupe|d=s threads|t augment|a sort|s=s reverse|r offset=i remote! local! external! pretty include|I=s@ exclude=s@ only=s@ jobs|j=s globoff|g stdin| - mua=s no-torsocks torsocks=s verbose|v+ quiet|q), + alert=s@ mua=s no-torsocks torsocks=s verbose|v+ quiet|q), PublicInbox::LeiQuery::curl_opt(), opt_dash('limit|n=i', '[0-9]+') ], 'show' => [ 'MID|OID', 'show a given object (Message-ID or object ID)', @@ -227,6 +227,11 @@ my %OPTDESC = ( 'show threads|t' => 'display entire thread a message belongs to', 'q threads|t' => 'return all messages in the same threads as the actual match(es)', +'alert=s@' => ['CMD,-WINCH,-bell,', + 'run command(s) or perform ops when done writing to output ' . + '(default: "-WINCH,-bell" with --mua and Maildir/IMAP output, ' . + 'nothing otherwise)' ], + 'augment|a' => 'augment --output destination instead of clobbering', 'output|mfolder|o=s' => [ 'MFOLDER', @@ -739,21 +744,43 @@ sub start_mua { if (my $sock = $self->{sock}) { # lei(1) client process runs it send($sock, exec_buf(\@cmd, {}), MSG_EOR); } elsif ($self->{oneshot}) { - $self->{"mua.pid.$self.$$"} = spawn(\@cmd); + $self->{"pid.$self.$$"}->{spawn(\@cmd)} = \@cmd; } if ($self->{lxs} && $self->{au_done}) { # kick wait_startq syswrite($self->{au_done}, 'q' x ($self->{lxs}->{jobs} // 0)); } + $self->{opt}->{quiet} = 1; + delete $self->{-progress}; + delete $self->{opt}->{verbose}; } sub poke_mua { # forces terminal MUAs to wake up and hopefully notice new mail my ($self) = @_; - return unless $self->{opt}->{mua} && -t $self->{1}; - # hit the process group that started the MUA - if (my $s = $self->{sock}) { - send($s, '-WINCH', MSG_EOR); - } elsif ($self->{oneshot}) { - kill('-WINCH', $$); + my $alerts = $self->{opt}->{alert} // return; + while (my $op = shift(@$alerts)) { + if ($op eq '-WINCH') { + # hit the process group that started the MUA + if ($self->{sock}) { + send($self->{sock}, '-WINCH', MSG_EOR); + } elsif ($self->{oneshot}) { + kill('-WINCH', $$); + } + } elsif ($op eq '-bell') { + out($self, "\a"); + } elsif ($op =~ /(?{sock}) { + send($s, exec_buf($cmd, {}), MSG_EOR); + } elsif ($self->{oneshot}) { + $self->{"pid.$self.$$"}->{spawn($cmd)} = $cmd; + } + } else { + err($self, "W: unsupported --alert=$op"); # non-fatal + } } } @@ -776,8 +803,8 @@ sub start_pager { my $fds = [ map { fileno($_) } @$rdr{0..2} ]; $send_cmd->($sock, $fds, exec_buf([$pager], $new_env), MSG_EOR); } elsif ($self->{oneshot}) { - $pgr->[0] = spawn([$pager], $new_env, $rdr); - $pgr->[3] = $$; # ew'll reap it + my $cmd = [$pager]; + $self->{"pid.$self.$$"}->{spawn($cmd, $new_env, $rdr)} = $cmd; } else { die 'BUG: start_pager w/o socket'; } @@ -793,8 +820,6 @@ sub stop_pager { $self->{2} = $pgr->[2]; # do not restore original stdout, just close it so we error out close(delete($self->{1})) if $self->{1}; - my $pid = $pgr->[0]; - dwaitpid($pid) if $pid && ($pgr->[3] // 0) == $$; } sub accept_dispatch { # Listener {post_accept} callback @@ -1044,9 +1069,8 @@ sub DESTROY { my ($self) = @_; $self->{1}->autoflush(1) if $self->{1}; stop_pager($self); - if (my $mua_pid = delete $self->{"mua.pid.$self.$$"}) { - waitpid($mua_pid, 0); - } + my $oneshot_pids = delete $self->{"pid.$self.$$"} or return; + waitpid($_, 0) for keys %$oneshot_pids; } 1; diff --git a/lib/PublicInbox/LeiOverview.pm b/lib/PublicInbox/LeiOverview.pm index f0ac4684..98c89d12 100644 --- a/lib/PublicInbox/LeiOverview.pm +++ b/lib/PublicInbox/LeiOverview.pm @@ -98,7 +98,10 @@ sub new { $opt->{'sort'} //= 'docid' if $dst ne '/dev/stdout'; $lei->{l2m} = eval { PublicInbox::LeiToMail->new($lei) }; return $lei->fail($@) if $@; - $lei->{early_mua} = 1 if $opt->{mua} && $lei->{l2m}->lock_free; + if ($opt->{mua} && $lei->{l2m}->lock_free) { + $lei->{early_mua} = 1; + $opt->{alert} //= [ '-WINCH,-bell' ] if -t $lei->{1}; + } } $self; }