X-Git-Url: http://www.git.stargrave.org/?p=public-inbox.git;a=blobdiff_plain;f=lib%2FPublicInbox%2FLEI.pm;h=9ab91714d0b8b725fdda3b92889b70574dce6b83;hp=5b726f71382e8732b43fae61bfcb6149e874a8a0;hb=6b52fe53a1f9e69a6ecfce16216a1fa180e4645f;hpb=bb0eab1051318528011252866b592735981084a5 diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index 5b726f71..9ab91714 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2021 all contributors +# Copyright (C) all contributors # License: AGPL-3.0+ # Backend for `lei' (local email interface). Unlike the C10K-oriented @@ -19,7 +19,7 @@ use IO::Handle (); use Fcntl qw(SEEK_SET); use PublicInbox::Config; use PublicInbox::Syscall qw(EPOLLIN); -use PublicInbox::DS qw(now dwaitpid); +use PublicInbox::DS qw(dwaitpid); use PublicInbox::Spawn qw(spawn popen_rd); use PublicInbox::Lock; use PublicInbox::Eml; @@ -130,9 +130,10 @@ sub url_folder_cache { sub ale { my ($self) = @_; - $self->{ale} //= do { + $self->{ale} // do { require PublicInbox::LeiALE; - $self->_lei_cfg(1)->{ale} //= PublicInbox::LeiALE->new($self); + my $cfg = $self->_lei_cfg(1); + $self->{ale} = $cfg->{ale} //= PublicInbox::LeiALE->new($self); }; } @@ -179,7 +180,7 @@ our %CMD = ( # sorted in order of importance/use: 'up' => [ 'OUTPUT...|--all', 'update saved search', qw(jobs|j=s lock=s@ alert=s@ mua=s verbose|v+ exclude=s@ - remote-fudge-time=s all:s remote! local! external!), @c_opt ], + remote-fudge-time=s all:s remote! local! external!), @net_opt, @c_opt ], 'lcat' => [ '--stdin|MSGID_OR_URL...', 'display local copy of message(s)', 'stdin|', # /|\z/ must be first for lone dash @@ -202,7 +203,7 @@ our %CMD = ( # sorted in order of importance/use: 'mail-diff' => [ '--stdin|LOCATION...', 'diff the contents of emails', 'stdin|', # /|\z/ must be first for lone dash - qw(verbose|v+ color:s no-color raw-header), + qw(verbose|v+ in-format|F=s color:s no-color raw-header), @diff_opt, @net_opt, @c_opt ], 'add-external' => [ 'LOCATION', @@ -215,15 +216,15 @@ our %CMD = ( # sorted in order of importance/use: 'ls-mail-sync' => [ '[FILTER]', 'list mail sync folders', qw(z|0 globoff|g invert-match|v local remote), @c_opt ], 'ls-mail-source' => [ 'URL', 'list IMAP or NNTP mail source folders', - qw(z|0 ascii l pretty url), @c_opt ], + qw(z|0 ascii l pretty url), @net_opt, @c_opt ], 'forget-external' => [ 'LOCATION...|--prune', 'exclude further results from a publicinbox|extindex', qw(prune), @c_opt ], 'ls-search' => [ '[PREFIX]', 'list saved search queries', qw(format|f=s pretty l ascii z|0), @c_opt ], -'forget-search' => [ 'OUTPUT...', 'forget a saved search', - qw(verbose|v+), @c_opt ], +'forget-search' => [ 'OUTPUT...|--prune', 'forget a saved search', + qw(verbose|v+ prune:s), @c_opt ], 'edit-search' => [ 'OUTPUT', "edit saved search via `git config --edit'", @c_opt ], 'rm' => [ '--stdin|LOCATION...', @@ -265,7 +266,8 @@ our %CMD = ( # sorted in order of importance/use: 'forget-mail-sync' => [ 'LOCATION...', 'forget sync information for a mail folder', @c_opt ], 'refresh-mail-sync' => [ 'LOCATION...|--all', - 'prune dangling sync data for a mail folder', 'all:s', @c_opt ], + 'prune dangling sync data for a mail folder', 'all:s', + @net_opt, @c_opt ], 'export-kw' => [ 'LOCATION...|--all', 'one-time export of keywords of sync sources', qw(all:s mode=s), @net_opt, @c_opt ], @@ -273,9 +275,9 @@ our %CMD = ( # sorted in order of importance/use: 'one-time conversion from URL or filesystem to another format', qw(stdin| in-format|F=s out-format|f=s output|mfolder|o=s lock=s@ kw!), @net_opt, @c_opt ], -'p2q' => [ 'FILE|COMMIT_OID|--stdin', +'p2q' => [ 'LOCATION_OR_COMMIT...|--stdin', "use a patch to generate a query for `lei q --stdin'", - qw(stdin| want|w=s@ uri debug), @c_opt ], + qw(stdin| in-format|F=s want|w=s@ uri debug), @net_opt, @c_opt ], 'config' => [ '[...]', sub { 'git-config(1) wrapper for '._config_path($_[0]); }, qw(config-file|system|global|file|f=s), # for conflict detection @@ -353,6 +355,7 @@ my %OPTDESC = ( 'want|w=s@' => [ 'PREFIX|dfpost|dfn', # common ones in help... 'search prefixes to extract (default: dfpost7)' ], +'uri p2q' => [ 'URI escape output' ], 'alert=s@' => ['CMD,:WINCH,:bell,', 'run command(s) or perform ops when done writing to output ' . @@ -408,6 +411,9 @@ my %OPTDESC = ( 'url ls-mail-source' => 'show full URL of newsgroup or IMAP folder', 'format|f=s ls-external' => $ls_format, +'prune:s forget-search' => + ['TYPE|local|remote', 'prune all, remote or local folders' ], + 'limit|n=i@' => ['NUM', 'limit on number of matches (default: 10000)' ], 'offset=i' => ['OFF', 'search result offset (default: 0)'], @@ -628,7 +634,10 @@ sub pkt_ops { sub workers_start { my ($lei, $wq, $jobs, $ops, $flds) = @_; - $ops = pkt_ops($lei, { ($ops ? %$ops : ()) }); + $ops //= {}; + ($wq->can('net_merge_all_done') && $lei->{auth}) and + $lei->{auth}->op_merge($ops, $wq, $lei); + pkt_ops($lei, $ops); $ops->{''} //= [ $wq->can('_lei_wq_eof') || \&wq_eof, $lei ]; my $end = $lei->pkt_op_pair; my $ident = $wq->{-wq_ident} // "lei-$lei->{cmd} worker"; @@ -645,12 +654,22 @@ sub workers_start { # call this when we're ready to wait on events and yield to other clients sub wait_wq_events { my ($lei, $op_c, $ops) = @_; + my $wq1 = $lei->{wq1}; + ($wq1 && $wq1->can('net_merge_all_done') && !$lei->{auth}) and + $wq1->net_merge_all_done; for my $wq (grep(defined, @$lei{qw(ikw pmd)})) { # auxiliary WQs $wq->wq_close; } $op_c->{ops} = $ops; } +sub wq1_start { + my ($lei, $wq, $jobs) = @_; + my ($op_c, $ops) = workers_start($lei, $wq, $jobs // 1); + $lei->{wq1} = $wq; + wait_wq_events($lei, $op_c, $ops); # net_merge_all_done if !{auth} +} + sub _help { require PublicInbox::LeiHelp; PublicInbox::LeiHelp::call($_[0], $_[1], \%CMD, \%OPTDESC); @@ -799,7 +818,8 @@ sub dispatch { next if $d eq ''; # same as git(1) chdir $d or return fail($self, "cd $d: $!"); } - open $self->{3}, '.' or return fail($self, "open . $!"); + open $self->{3}, '<', '.' or + return fail($self, "open . $!"); } $cb->($self, @argv); } elsif (grep(/\A-/, $cmd, @argv)) { # --help or -h only @@ -1125,10 +1145,12 @@ sub event_step { local %ENV = %{$self->{env}}; local $current_lei = $self; eval { - my @fds = $recv_cmd->($self->{sock}, my $buf, 4096); + my @fds = $recv_cmd->($self->{sock} // return, my $buf, 4096); if (scalar(@fds) == 1 && !defined($fds[0])) { return if $! == EAGAIN; die "recvmsg: $!" if $! != ECONNRESET; + $buf = ''; + @fds = (); # for open loop below: } for (@fds) { open my $rfh, '+<&=', $_ } if ($buf eq '') { @@ -1156,10 +1178,10 @@ sub event_step { sub event_step_init { my ($self) = @_; my $sock = $self->{sock} or return; - $self->{-event_init_done} //= do { # persist til $ops done + $self->{-event_init_done} // do { # persist til $ops done $sock->blocking(0); $self->SUPER::new($sock, EPOLLIN); - $sock; + $self->{-event_init_done} = $sock; }; } @@ -1198,7 +1220,7 @@ sub dir_idle_handler ($) { # PublicInbox::DirIdle callback my $fn = $ev->fullname; if ($fn =~ m!\A(.+)/(new|cur)/([^/]+)\z!) { # Maildir file my ($mdir, $nc, $bn) = ($1, $2, $3); - $nc = '' if $ev->IN_DELETE; + $nc = '' if $ev->IN_DELETE || $ev->IN_MOVED_FROM; for my $f (keys %{$MDIR2CFGPATH->{$mdir} // {}}) { my $cfg = $PATH2CFG{$f} // next; eval { @@ -1315,11 +1337,10 @@ sub lazy_start { $quit->(); } return 1 if defined($path); - my $now = now(); my $n = 0; for my $s (values %$dmap) { $s->can('busy') or next; - if ($s->busy($now)) { + if ($s->busy) { ++$n; } else { $s->close; @@ -1482,11 +1503,11 @@ sub git_oid { } sub lms { - my ($lei, $rw) = @_; + my ($lei, $creat) = @_; my $sto = $lei->{sto} // _lei_store($lei) // return; require PublicInbox::LeiMailSync; my $f = "$sto->{priv_eidx}->{topdir}/mail_sync.sqlite3"; - (-f $f || $rw) ? PublicInbox::LeiMailSync->new($f) : undef; + (-f $f || $creat) ? PublicInbox::LeiMailSync->new($f) : undef; } sub sto_done_request {