]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
admin: resolve_git_dir respects symlinks
authorEric Wong <e@80x24.org>
Tue, 28 Nov 2023 14:56:25 +0000 (14:56 +0000)
committerEric Wong <e@80x24.org>
Wed, 29 Nov 2023 02:13:25 +0000 (02:13 +0000)
Absolute pathnames of git coderepos are stored in the cindex,
but we should favor paths relative to $ENV{PWD} since it
respects symlinks in the heirarchy.

Respecting symlinks makes it easier to migrate cindex to
new storage as old storage wears out and to relocate the
storage device onto another machine.

lib/PublicInbox/Admin.pm
t/admin.t

index 893f4a1b20b7da989926cfba097299201d42822d..cc9d21719443388359b8de13847ecb1f69b0b5b0 100644 (file)
@@ -63,15 +63,32 @@ sub resolve_inboxdir {
        $dir;
 }
 
+sub valid_pwd {
+       my $pwd = $ENV{PWD} // return;
+       my @st_pwd = stat $pwd or return;
+       my @st_cwd = stat '.' or die "stat(.): $!";
+       "@st_pwd[1,0]" eq "@st_cwd[1,0]" ? $pwd : undef;
+}
+
 sub resolve_git_dir {
-       my ($cd) = @_;
+       my ($cd) = @_; # cd may be `undef' for cwd
        # try v1 bare git dirs
+       my $pwd = valid_pwd();
+       my $env;
+       defined($pwd) && substr($cd // '/', 0, 1) ne '/' and
+               $env->{PWD} = "$pwd/$cd";
        my $cmd = [ qw(git rev-parse --git-dir) ];
-       my $dir = run_qx($cmd, undef, {-C => $cd});
+       my $dir = run_qx($cmd, $env, { -C => $cd });
        die "error in @$cmd (cwd:${\($cd // '.')}): $?\n" if $?;
        chomp $dir;
-       # --absolute-git-dir requires git v2.13.0+
-       $dir = rel2abs_collapsed($dir, $cd) if $dir !~ m!\A/!;
+       # --absolute-git-dir requires git v2.13.0+, and we want to
+       # respect symlinks when $ENV{PWD} if $ENV{PWD} ne abs_path('.')
+       # since we store absolute GIT_DIR paths in cindex.
+       if (substr($dir, 0, 1) ne '/') {
+               substr($cd // '/', 0, 1) eq '/' or
+                       $cd = File::Spec->rel2abs($cd, $pwd);
+               $dir = rel2abs_collapsed($dir, $cd);
+       }
        $dir;
 }
 
index 20e3deb7956bc1d61dc98084b81d68de68541bab..586938d0ba5e6c8d184fbb2089c6db1cc62165bf 100644 (file)
--- a/t/admin.t
+++ b/t/admin.t
@@ -6,6 +6,7 @@ use v5.10.1;
 use PublicInbox::TestCommon;
 use PublicInbox::Import;
 use_ok 'PublicInbox::Admin';
+use autodie;
 my $v1 = create_inbox 'v1', -no_gc => 1, sub {};
 my ($tmpdir, $for_destroy) = tmpdir();
 my $git_dir = $v1->{inboxdir};
@@ -23,6 +24,17 @@ SKIP: {
 };
 
 *resolve_inboxdir = \&PublicInbox::Admin::resolve_inboxdir;
+*resolve_git_dir = \&PublicInbox::Admin::resolve_git_dir;
+
+{
+       symlink $git_dir, my $sym = "$tmpdir/v1-symlink.git";
+       for my $d ('') { # TODO: should work inside $sym/objects
+               local $ENV{PWD} = $sym.$d;
+               chdir $sym.$d;
+               is resolve_git_dir('.'), $sym,
+                       "symlink preserved from {SYMLINKDIR}.git$d";
+       }
+}
 
 # v1
 is(resolve_inboxdir($git_dir), $git_dir, 'top-level GIT_DIR resolved');