]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/LeiMirror.pm
lei_mirror: support {symlinks} from manifest
[public-inbox.git] / lib / PublicInbox / LeiMirror.pm
index f7db5a494e09f36ffdd0780379270298bdbf9355..47db9ccd8c3ef8e002d3e034a4b81679d278c766 100644 (file)
@@ -664,6 +664,7 @@ sub up_fp_done {
        push @{$self->{chg}->{fp_mismatch}}, $self->{-key};
 }
 
+# modifies the to-be-written manifest entry, and sets values from it, too
 sub update_ent {
        my ($self) = @_;
        my $key = $self->{-key} // die 'BUG: no -key';
@@ -678,6 +679,42 @@ sub update_ent {
                my $done = PublicInbox::OnDestroy->new($$, \&up_fp_done, $self);
                start_cmd($self, $cmd, $opt, $done);
        }
+
+       $new = $self->{-ent}->{head};
+       $cur = $self->{-local_manifest}->{$key}->{head} // "\0";
+       if (defined($new) && $new ne $cur) {
+               # n.b. grokmirror writes raw contents to $dst/HEAD w/o locking
+               my $cmd = [ 'git', "--git-dir=$dst" ];
+               if ($new =~ s/\Aref: //) {
+                       push @$cmd, qw(symbolic-ref HEAD), $new;
+               } elsif ($new =~ /\A[a-f0-9]{40,}\z/) {
+                       push @$cmd, qw(update-ref --no-deref HEAD), $new;
+               } else {
+                       undef $cmd;
+                       warn "W: $key: {head} => `$new' not understood\n";
+               }
+               start_cmd($self, $cmd, { 2 => $self->{lei}->{2} }) if $cmd;
+       }
+       if (my $symlinks = $self->{-ent}->{symlinks}) {
+               my $top = File::Spec->rel2abs($self->{dst});
+               for my $p (@$symlinks) {
+                       my $ln = "$top/$p";
+                       $ln =~ tr!/!/!s;
+                       my (undef, $dn, $bn) = File::Spec->splitpath($ln);
+                       File::Path::mkpath($dn);
+                       my $tgt = "$top/$key";
+                       $tgt = File::Spec->abs2rel($tgt, $dn);
+                       if (lstat($ln)) {
+                               if (-l _) {
+                                       next if readlink($ln) eq $tgt;
+                                       unlink($ln) or die "unlink($ln): $!";
+                               } else {
+                                       push @{$self->{chg}->{badlink}}, $p;
+                               }
+                       }
+                       symlink($tgt, $ln) or die "symlink($tgt, $ln): $!";
+               }
+       }
        $new = $self->{-ent}->{owner} // return;
        $cur = $self->{-local_manifest}->{$key}->{owner} // "\0";
        return if $cur eq $new;
@@ -1042,6 +1079,10 @@ W: The above fingerprints may never match without --prune
 EOM
        }
        dump_manifest($m => $ft) if delete($self->{chg}->{manifest}) || $mis;
+       my $bad = delete $self->{chg}->{badlink};
+       warn(<<EOM, map { ("\t", $_, "\n") } @$bad) if $bad;
+W: The following exist and have not been converted to symlinks
+EOM
        ft_rename($ft, $manifest, 0666);
 }