unofficial mirror of meta@public-inbox.org
 help / color / mirror / Atom feed
* [PATCH] lei_mail_sync: Maildir canonicalization omits trailing slash
@ 2021-05-06  2:22 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2021-05-06  2:22 UTC (permalink / raw)
  To: meta

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(<<EOM, undef, $folder, $fid) if $rw;
+UPDATE folders SET loc = ? WHERE fid = ?
+EOM
+			return $fid;
+		}
+	# sometimes we stored trailing slash..
+	} elsif ($folder =~ m!\A(?:maildir|mh):!i) {
+		($fid) = $dbh->selectrow_array($sel, undef, "$folder/");
+		if (defined $fid) {
+			$dbh->do(<<EOM, undef, $folder, $fid) if $rw;
+UPDATE folders SET loc = ? WHERE fid = ?
+EOM
+			return $fid;
+		}
+	}
 	return unless $rw;
 
-	($row) = $dbh->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 {

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2021-05-06  2:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-06  2:22 [PATCH] lei_mail_sync: Maildir canonicalization omits trailing slash Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).