MANIFEST | 1 + lib/PublicInbox/LEI.pm | 2 ++ lib/PublicInbox/LeiQuery.pm | 2 +- lib/PublicInbox/LeiSavedSearch.pm | 24 ++++++++++++++++-------- lib/PublicInbox/LeiToMail.pm | 12 +++++++----- lib/PublicInbox/LeiUp.pm | 46 ++++++++++++++++++++++++++++++++++++++++++++++ t/lei-q-save.t | 17 +++++++++++++++-- diff --git a/MANIFEST b/MANIFEST index 20615abcdf9e663278ebfb3fdc9f5a60deeb5110..1b7d16ee045869bf49eb83ad1a7d17347c156462 100644 --- a/MANIFEST +++ b/MANIFEST @@ -208,6 +208,7 @@ lib/PublicInbox/LeiStoreErr.pm lib/PublicInbox/LeiSucks.pm lib/PublicInbox/LeiTag.pm lib/PublicInbox/LeiToMail.pm +lib/PublicInbox/LeiUp.pm lib/PublicInbox/LeiXSearch.pm lib/PublicInbox/Linkify.pm lib/PublicInbox/Listener.pm diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index 7292d0f22c344f08cc7774d5830f2fdffceb231a..4b87c104bec98df6936a4af1dc81d56e57f41ee9 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -135,6 +135,8 @@ qw(save output|mfolder|o=s format|f=s dedupe|d=s threads|t+ sort|s=s reverse|r offset=i pretty jobs|j=s globoff|g augment|a import-before! lock=s@ rsyncable alert=s@ mua=s verbose|v+), @c_opt, opt_dash('limit|n=i', '[0-9]+') ], +'up' => [ 'SEARCH_TERMS...', 'update saved search', + qw(jobs|j=s lock=s@ alert=s@ mua=s verbose|v+), @c_opt ], 'blob' => [ 'OID', 'show a git blob, reconstructing from mail if necessary', qw(git-dir=s@ cwd! verbose|v+ mail! oid-a|A=s path-a|a=s path-b|b=s), diff --git a/lib/PublicInbox/LeiQuery.pm b/lib/PublicInbox/LeiQuery.pm index 8bca102058afabb7ff00d70d5338b5c5131f1557..7456f7f98e212bbba3295b1484ba0a13bcd8c620 100644 --- a/lib/PublicInbox/LeiQuery.pm +++ b/lib/PublicInbox/LeiQuery.pm @@ -12,7 +12,7 @@ my ($lxs, $exclude, $loc) = @_; $lxs->prepare_external($loc) unless $exclude->{$loc}; } -sub _start_query { +sub _start_query { # used by "lei q" and "lei up" my ($self) = @_; PublicInbox::LeiOverview->new($self) or return; my $opt = $self->{opt}; diff --git a/lib/PublicInbox/LeiSavedSearch.pm b/lib/PublicInbox/LeiSavedSearch.pm index ab9f393b2be8a37bd403d54c914a8a52dac88281..815008fd4d7dd7ac3ac6334afb40e0d112600097 100644 --- a/lib/PublicInbox/LeiSavedSearch.pm +++ b/lib/PublicInbox/LeiSavedSearch.pm @@ -17,18 +17,12 @@ sub new { my ($cls, $lei, $dir) = @_; my $self = bless { ale => $lei->ale, -cfg => {} }, $cls; - if (defined $dir) { # updating existing saved search + if (defined $dir) { # updating existing saved search via "lei up" my $f = $self->{'-f'} = "$dir/lei.saved-search"; -f $f && -r _ or return $lei->fail("$f non-existent or unreadable"); $self->{-cfg} = PublicInbox::Config::git_config_dump($f); - my $q = $lei->{mset_opt}->{q_raw} = $self->{-cfg}->{'lei.q'} // - return $lei->fail("lei.q unset in $f"); - my $lse = $lei->{lse} // die 'BUG: {lse} missing'; - $lei->{mset_opt}->{qstr} = ref($q) ? - $lse->query_argv_to_string($lse->git, $q) : - $lse->query_approxidate($lse->git, $q); - } else { # new saved search + } else { # new saved search "lei q --save" my $saved_dir = $lei->store_path . '/../saved-searches/'; my (@name) = ($lei->{ovv}->{dst} =~ m{([\w\-\.]+)/*\z}); push @name, to_filename($lei->{mset_opt}->{qstr}); @@ -41,6 +35,20 @@ if (ref $q) { cfg_set($self, '--add', 'lei.q', $_) for @$q; } else { cfg_set($self, 'lei.q', $q); + } + my $fmt = $lei->{opt}->{'format'}; + cfg_set($self, 'lei.q.format', $fmt) if defined $fmt; + cfg_set($self, 'lei.q.output', $lei->{opt}->{output}); + for my $k (qw(only include exclude)) { + my $ary = $lei->{opt}->{$k} // next; + for my $x (@$ary) { + cfg_set($self, '--add', "lei.q.$k", $x); + } + } + for my $k (qw(external local remote import-remote + import-before threads)) { + my $val = $lei->{opt}->{$k} // next; + cfg_set($self, "lei.q.$k", $val); } } bless $self->{-cfg}, 'PublicInbox::Config'; diff --git a/lib/PublicInbox/LeiToMail.pm b/lib/PublicInbox/LeiToMail.pm index bd2b714a1d68c75b307b4ce23c9c88467ce864d8..4ebaf8f347371d661e4473329ab3ef4dc23dd8e3 100644 --- a/lib/PublicInbox/LeiToMail.pm +++ b/lib/PublicInbox/LeiToMail.pm @@ -349,11 +349,13 @@ } else { die "bad mail --format=$fmt\n"; } $self->{dst} = $dst; - my $dd_cls = 'PublicInbox::'. - ($lei->{opt}->{save} ? 'LeiSavedSearch' : 'LeiDedupe'); - eval "require $dd_cls"; - die "$dd_cls: $@" if $@; - $lei->{dedupe} = $dd_cls->new($lei); + $lei->{dedupe} = $lei->{lss} // do { + my $dd_cls = 'PublicInbox::'. + ($lei->{opt}->{save} ? 'LeiSavedSearch' : 'LeiDedupe'); + eval "require $dd_cls"; + die "$dd_cls: $@" if $@; + $dd_cls->new($lei); + }; $self; } diff --git a/lib/PublicInbox/LeiUp.pm b/lib/PublicInbox/LeiUp.pm new file mode 100644 index 0000000000000000000000000000000000000000..386a75667a815577d2126234e044efafb5b62155 --- /dev/null +++ b/lib/PublicInbox/LeiUp.pm @@ -0,0 +1,46 @@ +# Copyright (C) 2021 all contributors +# License: AGPL-3.0+ + +# "lei up" - updates the result of "lei q --save" +package PublicInbox::LeiUp; +use strict; +use v5.10.1; +use PublicInbox::LeiSavedSearch; +use PublicInbox::LeiOverview; + +sub lei_up { + my ($lei, $dir) = @_; + $lei->{lse} = $lei->_lei_store(1)->search; + my $lss = PublicInbox::LeiSavedSearch->new($lei, $dir) or return; + my $mset_opt = $lei->{mset_opt} = { relevance => -2 }; + $mset_opt->{limit} = $lei->{opt}->{limit} // 10000; + my $q = $mset_opt->{q_raw} = $lss->{-cfg}->{'lei.q'} // + return $lei->fail("lei.q unset in $lss->{-f}"); + my $lse = $lei->{lse} // die 'BUG: {lse} missing'; + if (ref($q)) { + $mset_opt->{qstr} = $lse->query_argv_to_string($lse->git, $q); + } else { + $lse->query_approxidate($lse->git, $mset_opt->{qstr} = $q); + } + $lei->{opt}->{output} = $lss->{-cfg}->{'lei.q.output'} // + return $lei->fail("lei.q.output unset in $lss->{-f}"); + $lei->{opt}->{'format'} //= $lss->{-cfg}->{'lei.q.format'}; # optional + + my $to_avref = $lss->{-cfg}->can('_array'); + for my $k (qw(only include exclude)) { + my $v = $lss->{-cfg}->{"lei.q.$k"} // next; + $lei->{opt}->{$k} = $to_avref->($v); + } + for my $k (qw(external local remote + import-remote import-before threads)) { + my $v = $lss->{-cfg}->{"lei.q.$k"} // next; + $lei->{opt}->{$k} = $v; + } + $lei->{lss} = $lss; # for LeiOverview->new + my $lxs = $lei->lxs_prepare or return; + $lei->ale->refresh_externals($lxs); + $lei->{opt}->{save} = 1; + $lei->_start_query; +} + +1; diff --git a/t/lei-q-save.t b/t/lei-q-save.t index 56f7cb373bf182d76c8283ba27dd4c6439dc821d..a6d579cfcf1bca21311ed2556ceb01ef6c2e5e71 100644 --- a/t/lei-q-save.t +++ b/t/lei-q-save.t @@ -2,11 +2,24 @@ #!perl -w # Copyright (C) 2021 all contributors # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; +my $doc1 = eml_load('t/plack-qp.eml'); +my $doc2 = eml_load('t/utf8.eml'); test_lei(sub { my $home = $ENV{HOME}; - lei_ok qw(import t/plack-qp.eml); - lei_ok qw(q --save z:0..), '-o', "$home/md/"; + lei_ok qw(import -q t/plack-qp.eml); + lei_ok qw(q -q --save z:0..), '-o', "$home/md/"; + my %before = map { $_ => 1 } glob("$home/md/cur/*"); + is_deeply(eml_load((keys %before)[0]), $doc1, 'doc1 matches'); + my @s = glob("$home/.local/share/lei/saved-searches/md-*"); is(scalar(@s), 1, 'got one saved search'); + + # ensure "lei up" works, since it compliments "lei q --save" + lei_ok qw(import t/utf8.eml); + lei_ok qw(up), $s[0]; + my %after = map { $_ => 1 } glob("$home/md/cur/*"); + is(delete $after{(keys(%before))[0]}, 1, 'original message kept'); + is(scalar(keys %after), 1, 'one new message added'); + is_deeply(eml_load((keys %after)[0]), $doc2, 'doc2 matches'); }); done_testing;