about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2022-12-28 02:56:56 +0000
committerEric Wong <e@80x24.org>2022-12-30 09:46:50 +0000
commit6efe57a87e6a7da471adf31c037844add788a61a (patch)
treef84a1e7844832859f7056ad28a216043ac54ab96
parent323b120f3c82dd02e7e54ef75bd383cba4b125e3 (diff)
downloadpublic-inbox-6efe57a87e6a7da471adf31c037844add788a61a.tar.gz
This should be compatible with both grokmirror 1 and 2 behavior
and serialized on a per-repo basis.
-rw-r--r--MANIFEST2
-rw-r--r--lib/PublicInbox/LeiMirror.pm24
-rwxr-xr-xscript/public-inbox-clone2
-rwxr-xr-xt/clone-coderepo-puh1.sh6
-rwxr-xr-xt/clone-coderepo-puh2.sh6
-rw-r--r--t/clone-coderepo.t22
6 files changed, 61 insertions, 1 deletions
diff --git a/MANIFEST b/MANIFEST
index 2966a121..37357663 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -396,6 +396,8 @@ t/altid.t
 t/altid_v2.t
 t/cgi.t
 t/check-www-inbox.perl
+t/clone-coderepo-puh1.sh
+t/clone-coderepo-puh2.sh
 t/clone-coderepo.psgi
 t/clone-coderepo.t
 t/cmd_ipc.t
diff --git a/lib/PublicInbox/LeiMirror.pm b/lib/PublicInbox/LeiMirror.pm
index 9843d1a6..5952ed52 100644
--- a/lib/PublicInbox/LeiMirror.pm
+++ b/lib/PublicInbox/LeiMirror.pm
@@ -682,6 +682,22 @@ sub atomic_write ($$$) {
         ft_rename($ft, "$dn/$bn", 0666);
 }
 
+sub run_next_puh {
+        my ($self) = @_;
+        my $puh = shift @{$self->{-puh_todo}} // return;
+        my $fini = PublicInbox::OnDestroy->new($$, \&run_next_puh, $self);
+        my $cmd = [ @$puh, ($self->{cur_dst} // $self->{dst}) ];
+        my $opt = +{ map { $_ => $self->{lei}->{$_} } (0..2) };
+        start_cmd($self, $cmd, undef, $opt, $fini);
+}
+
+sub run_post_update_hooks {
+        my ($self) = @_;
+        my $puh = $self->{-puh} // return;
+        @{$self->{-puh_todo}} = @$puh;
+        run_next_puh($self);
+}
+
 # modifies the to-be-written manifest entry, and sets values from it, too
 sub update_ent {
         my ($self) = @_;
@@ -773,6 +789,7 @@ sub v1_done { # called via OnDestroy
         }
         eval { set_description($self) };
         warn $@ if $@;
+        run_post_update_hooks($self);
         return if ($self->{-is_epoch} ||
                 $self->{lei}->{opt}->{'inbox-config'} ne 'always');
         write_makefile($dst, 1);
@@ -1165,6 +1182,13 @@ sub do_mirror { # via wq_io_do or public-inbox-clone
         $self->{dry_run} = 1 if $lei->{opt}->{'dry-run'};
         umask($lei->{client_umask}) if defined $lei->{client_umask};
         $self->{-initial_clone} = 1 if !-d $self->{dst};
+        if (defined(my $puh = $lei->{opt}->{'post-update-hook'})) {
+                require Text::ParseWords;
+                for (@$puh) {
+                        my $pfx = [ Text::ParseWords::shellwords($_) ];
+                        push @{$self->{-puh}}, $pfx;
+                }
+        }
         eval {
                 my $ic = $lei->{opt}->{'inbox-config'} //= 'always';
                 $ic =~ /\A(?:v1|v2|always|never)\z/s or die <<"";
diff --git a/script/public-inbox-clone b/script/public-inbox-clone
index 677c56c8..6ed7ab6b 100755
--- a/script/public-inbox-clone
+++ b/script/public-inbox-clone
@@ -27,7 +27,7 @@ EOF
 # support both :/
 GetOptions($opt, qw(help|h quiet|q verbose|v+ C=s@ c=s@ include|I=s@ exclude=s@
         inbox-config=s inbox-version=i objstore=s manifest=s
-        project-list|projectslist=s
+        project-list|projectslist=s post-update-hook=s@
         prune|p keep-going|k
         dry-run|n jobs|j=i no-torsocks torsocks=s epoch=s)) or die $help;
 if ($opt->{help}) { print $help; exit };
diff --git a/t/clone-coderepo-puh1.sh b/t/clone-coderepo-puh1.sh
new file mode 100755
index 00000000..37a52bd4
--- /dev/null
+++ b/t/clone-coderepo-puh1.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# sample --post-update-hook for t/clone-coderepo.t test
+case $CLONE_CODEREPO_TEST_OUT in
+'') ;;
+*) echo "uno $@" >> "$CLONE_CODEREPO_TEST_OUT" ;;
+esac
diff --git a/t/clone-coderepo-puh2.sh b/t/clone-coderepo-puh2.sh
new file mode 100755
index 00000000..1170a08a
--- /dev/null
+++ b/t/clone-coderepo-puh2.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# sample --post-update-hook for t/clone-coderepo.t test
+case $CLONE_CODEREPO_TEST_OUT in
+'') ;;
+*) echo "dos $@" >> "$CLONE_CODEREPO_TEST_OUT" ;;
+esac
diff --git a/t/clone-coderepo.t b/t/clone-coderepo.t
index eb8f8b37..94721207 100644
--- a/t/clone-coderepo.t
+++ b/t/clone-coderepo.t
@@ -5,6 +5,7 @@ use v5.12;
 use PublicInbox::TestCommon;
 use PublicInbox::Import;
 use File::Temp;
+use File::Path qw(remove_tree);
 use Digest::SHA qw(sha1_hex);
 require_mods(qw(json Plack::Builder HTTP::Date HTTP::Status));
 require_git '1.8.5';
@@ -126,5 +127,26 @@ is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
         like($err, qr/no longer exist.*\bgone\.git\b/s, 'gone.git noted');
 }
 
+{
+        my $x = [qw(-clone --inbox-config=never --manifest= --project-list=
+                --objstore= -p), $url, "$tmpdir/dst",
+                '--post-update-hook=./t/clone-coderepo-puh1.sh',
+                '--post-update-hook=./t/clone-coderepo-puh2.sh' ];
+        my $log = "$tmpdir/puh.log";
+        my $env = { CLONE_CODEREPO_TEST_OUT => $log };
+        ok(run_script($x, $env), 'no-op clone w/ post-update-hook');
+        ok(!-e $log, 'hooks not run on no-op');
+        remove_tree("$tmpdir/dst");
+        ok(run_script($x, $env), 'fresh clone w/ post-update-hook');
+        ok(-e $log, 'hooks run on fresh clone');
+        open my $lh, '<', $log or xbail "open $log: $!";
+        chomp(my @l = readline($lh));
+        is(scalar(@l), 4, '4 lines written by hooks');
+        for my $r (qw(a b)) {
+                is_xdeeply(['uno', 'dos'],
+                        [ (map { s/ .+//; $_ } grep(m!/$r\.git\z!, @l)) ],
+                        "$r.git hooks ran in order") or diag explain(\@l);
+        }
+}
 
 done_testing;