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-ASN: 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 51D291F5AE for ; Thu, 6 May 2021 02:22:39 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH] lei_mail_sync: Maildir canonicalization omits trailing slash Date: Thu, 6 May 2021 02:22:39 +0000 Message-Id: <20210506022239.22663-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: We use trailing slashes internally, but should not increase visual noise for users by exposing them in config files or DB storage (and shell completion/listings). This fixes a long-standing bug in $lei->rel2abs that prevented absolute paths from being canonicalized. --- lib/PublicInbox/LEI.pm | 1 + lib/PublicInbox/LeiInspect.pm | 2 +- lib/PublicInbox/LeiMailSync.pm | 29 ++++++++++++++++++++++++----- lib/PublicInbox/LeiSavedSearch.pm | 2 -- t/lei-import-maildir.t | 5 ++++- t/lei-q-save.t | 9 ++++++--- t/lei_mail_sync.t | 12 ++++++++++++ 7 files changed, 48 insertions(+), 12 deletions(-) diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index 9dbbeba9..7349c261 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -70,6 +70,7 @@ sub rel2abs { my ($self, $p) = @_; if (index($p, '/') == 0) { # already absolute $p =~ tr!/!/!s; # squeeze redundant slashes + chop($p) if substr($p, -1, 1) eq '/'; return $p; } my $pwd = $self->{env}->{PWD}; diff --git a/lib/PublicInbox/LeiInspect.pm b/lib/PublicInbox/LeiInspect.pm index 714d2526..f79ebc9a 100644 --- a/lib/PublicInbox/LeiInspect.pm +++ b/lib/PublicInbox/LeiInspect.pm @@ -44,7 +44,7 @@ sub inspect_sync_folder ($$) { } @maybe; } } elsif ($folder =~ m!\A(maildir|mh):(.+)!i) { - my $type = $1; + my $type = lc $1; $folders[0] = "$type:".$lei->abs_path($2); } elsif (-d $folder) { $folders[0] = 'maildir:'.$lei->abs_path($folder); diff --git a/lib/PublicInbox/LeiMailSync.pm b/lib/PublicInbox/LeiMailSync.pm index 2e74e433..d8242de3 100644 --- a/lib/PublicInbox/LeiMailSync.pm +++ b/lib/PublicInbox/LeiMailSync.pm @@ -72,15 +72,34 @@ CREATE TABLE IF NOT EXISTS blob2name ( sub _fid_for { my ($self, $folder, $rw) = @_; my $dbh = $self->{dbh}; - my ($row) = $dbh->selectrow_array(<<'', undef, $folder); -SELECT fid FROM folders WHERE loc = ? LIMIT 1 + my $sel = 'SELECT fid FROM folders WHERE loc = ? LIMIT 1'; + my ($fid) = $dbh->selectrow_array($sel, undef, $folder); + return $fid if defined $fid; - return $row if defined $row; + if ($folder =~ s!\A((?:maildir|mh):.*?)/+\z!$1!i) { + warn "folder: $folder/ had trailing slash in arg\n"; + ($fid) = $dbh->selectrow_array($sel, undef, $folder); + if (defined $fid) { + $dbh->do(<selectrow_array($sel, undef, "$folder/"); + if (defined $fid) { + $dbh->do(<selectrow_array('SELECT MAX(fid) FROM folders'); + ($fid) = $dbh->selectrow_array('SELECT MAX(fid) FROM folders'); - my $fid = ($row // 0) + 1; + $fid += 1; # in case we're reusing, clobber existing stale refs: $dbh->do('DELETE FROM blob2name WHERE fid = ?', undef, $fid); $dbh->do('DELETE FROM blob2num WHERE fid = ?', undef, $fid); diff --git a/lib/PublicInbox/LeiSavedSearch.pm b/lib/PublicInbox/LeiSavedSearch.pm index 92ced28b..01b987d1 100644 --- a/lib/PublicInbox/LeiSavedSearch.pm +++ b/lib/PublicInbox/LeiSavedSearch.pm @@ -40,8 +40,6 @@ sub lss_dir_for ($$;$) { } else { # can't use Cwd::abs_path since dirname($$dstref) may not exist $$dstref = $lei->rel2abs($$dstref); - # Maildirs have trailing '/' internally - $$dstref .= '/' if -d $$dstref; $$dstref =~ tr!/!/!s; @n = ($$dstref =~ m{([^/]+)/*\z}); # basename } diff --git a/t/lei-import-maildir.t b/t/lei-import-maildir.t index b85d3026..f813440a 100644 --- a/t/lei-import-maildir.t +++ b/t/lei-import-maildir.t @@ -10,12 +10,15 @@ test_lei(sub { } symlink(abs_path('t/data/0001.patch'), "$md/cur/x:2,S") or BAIL_OUT "symlink $md $!"; - lei_ok(qw(import), $md, \'import Maildir'); + lei_ok(qw(import), "$md/", \'import Maildir'); my $imp_err = $lei_err; my %i; lei_ok('inspect', $md); $i{no_type} = $lei_out; + lei_ok('inspect', "$md/"); $i{no_type_tslash} = $lei_out; lei_ok('inspect', "maildir:$md"), $i{with_type} = $lei_out; + lei_ok('inspect', "maildir:$md/"), $i{with_type_tslash} = $lei_out; + lei_ok('inspect', "MAILDIR:$md"), $i{ALLCAPS} = $lei_out; lei_ok(['inspect', $md], undef, { -C => $ENV{HOME}, %$lei_opt }); $i{rel_no_type} = $lei_out; lei_ok(['inspect', "maildir:$md"], undef, diff --git a/t/lei-q-save.t b/t/lei-q-save.t index 9f65e4a2..753d5b20 100644 --- a/t/lei-q-save.t +++ b/t/lei-q-save.t @@ -23,13 +23,16 @@ test_lei(sub { my $home = $ENV{HOME}; my $in = $doc1->as_string; lei_ok [qw(import -q -F eml -)], undef, { 0 => \$in, %$lei_opt }; - lei_ok qw(q -q --save z:0.. d:last.week..), '-o', "$home/md/"; + lei_ok qw(q -q --save z:0.. d:last.week..), '-o', "MAILDIR:$home/md/"; my %before = map { $_ => 1 } glob("$home/md/cur/*"); is_deeply(eml_load((keys %before)[0]), $doc1, 'doc1 matches'); + lei_ok qw(ls-mail-sync); + is($lei_out, "maildir:$home/md\n", 'canonicalized mail sync name'); my @s = glob("$home/.local/share/lei/saved-searches/md-*"); is(scalar(@s), 1, 'got one saved search'); my $cfg = PublicInbox::Config->new("$s[0]/lei.saved-search"); + is($cfg->{'lei.q.output'}, "maildir:$home/md", 'canonicalized output'); is_deeply($cfg->{'lei.q'}, ['z:0..', 'd:last.week..'], 'store relative time, not parsed (absolute) timestamp'); @@ -66,14 +69,14 @@ test_lei(sub { lei_ok qw(ls-search); my @d = split(/\n/, $lei_out); lei_ok qw(ls-search -z); my @z = split(/\0/, $lei_out); is_deeply(\@d, \@z, '-z output matches non-z'); - is_deeply(\@d, [ "$home/mbcl2", "$home/md/" ], + is_deeply(\@d, [ "$home/mbcl2", "$home/md" ], 'ls-search output alphabetically sorted'); lei_ok qw(ls-search -l); my $json = PublicInbox::Config->json->decode($lei_out); ok($json && $json->[0]->{output}, 'JSON has output'); lei_ok qw(_complete lei up); like($lei_out, qr!^\Q$home/mbcl2\E$!sm, 'complete got mbcl2 output'); - like($lei_out, qr!^\Q$home/md/\E$!sm, 'complete got maildir output'); + like($lei_out, qr!^\Q$home/md\E$!sm, 'complete got maildir output'); unlink("$home/mbcl2") or xbail "unlink $!"; lei_ok qw(_complete lei up); diff --git a/t/lei_mail_sync.t b/t/lei_mail_sync.t index 864d6e48..f0605092 100644 --- a/t/lei_mail_sync.t +++ b/t/lei_mail_sync.t @@ -37,6 +37,18 @@ is_deeply($ro->locations_for('deadbeef'), { $imap => [ 1 ], $maildir => [ $fname ] }, 'locations_for w/ maildir + imap'); +if ('mess things up pretend old bug') { + $lms->lms_begin; + $lms->{dbh}->do('UPDATE folders SET loc = ? WHERE loc = ?', undef, + "$maildir/", $maildir); + ok(delete $lms->{fmap}, 'clear folder map'); + $lms->lms_commit; + + $lms->lms_begin; + ok($lms->set_src('deadbeef', $maildir, \$fname), 'set Maildir once'); + $lms->lms_commit; +}; + is_deeply([sort($ro->folders)], [$imap, $maildir], 'both folders shown'); my @res; $ro->each_src($maildir, sub {