2 # Copyright (C) all contributors <meta@public-inbox.org>
3 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
5 use PublicInbox::TestCommon;
6 use PublicInbox::Import;
8 use Digest::SHA qw(sha1_hex);
9 require_mods(qw(json Plack::Builder HTTP::Date HTTP::Status));
11 require_ok 'PublicInbox::LeiMirror';
12 my ($tmpdir, $for_destroy) = tmpdir();
13 my $pa = "$tmpdir/src/a.git";
14 my $pb = "$tmpdir/src/b.git";
15 PublicInbox::Import::init_bare($pa);
16 my ($stdout, $stderr) = ("$tmpdir/out.log", "$tmpdir/err.log");
17 my $pi_config = "$tmpdir/pi_config";
19 my $tcp = tcp_server();
20 my $url = 'http://'.tcp_host_port($tcp).'/';
21 my $set_manifest = sub {
23 $f //= "$tmpdir/src/manifest.js.gz";
24 my $ft = File::Temp->new(TMPDIR => $tmpdir, UNLINK => 0);
25 PublicInbox::LeiMirror::dump_manifest($m, $ft);
26 PublicInbox::LeiMirror::ft_rename($ft, $f, 0666);
28 my $read_manifest = sub {
30 open my $fh, '<', $f or xbail "open($f): $!";
31 PublicInbox::LeiMirror::decode_manifest($fh, $f, $f);
35 my $m; # manifest hashref
39 my $fi_data = './t/git.fast-import-data';
40 open $rdr->{0}, '<', $fi_data or xbail "open($fi_data): $!";
41 my @git = ('git', "--git-dir=$pa");
42 xsys_e([@git, qw(fast-import --quiet)], undef, $rdr);
43 xsys_e([qw(/bin/cp -Rp a.git b.git)], undef, { -C => "$tmpdir/src" });
44 open my $fh, '>', $pi_config or xbail "open($pi_config): $!";
45 print $fh <<EOM or xbail "print: $!";
47 cgitrc = $tmpdir/cgitrc
50 close $fh or xbail "close: $!";
52 my $f = "$tmpdir/cgitrc";
53 open $fh, '>', $f or xbail "open($f): $!";
54 print $fh <<EOM or xbail "print: $!";
55 project-list=$tmpdir/src/projects.list
58 close $fh or xbail "close($f): $!";
60 my $cmd = [ '-httpd', '-W0', "--stdout=$stdout", "--stderr=$stderr",
61 File::Spec->rel2abs('t/clone-coderepo.psgi') ];
62 my $env = { TEST_DOCROOT => "$tmpdir/src", PI_CONFIG => $pi_config };
63 $td = start_script($cmd, $env, { 3 => $tcp });
64 my $fp = sha1_hex(my $refs = xqx([@git, 'show-ref']));
78 $f = "$tmpdir/src/projects.list";
79 open $fh, '>', $f, or xbail "open($f): $!";
80 print $fh <<EOM or xbail "print($f): $!";
84 close $fh or xbail "close($f): $!";
87 my $cmd = [qw(-clone --inbox-config=never --manifest= --project-list=
88 --objstore= -p -q), $url, "$tmpdir/dst"];
89 ok(run_script($cmd), 'clone');
90 is(xqx([qw(git config gitweb.owner)], { GIT_DIR => "$tmpdir/dst/a.git" }),
91 "Alice\n", 'a.git gitweb.owner set');
92 is(xqx([qw(git config gitweb.owner)], { GIT_DIR => "$tmpdir/dst/b.git" }),
93 "Bob\n", 'b.git gitweb.owner set');
95 my $dst_pl = "$tmpdir/dst/projects.list";
96 my $dst_mf = "$tmpdir/dst/manifest.js.gz";
97 ok(!-d "$tmpdir/dst/objstore", 'no objstore created w/o forkgroups');
98 my $r = $read_manifest->($dst_mf);
99 is_deeply($r, $m, 'manifest matches');
101 is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
102 'wrote projects.list');
105 $m->{'/a.git'}->{symlinks} = [ '/old/a.git' ];
107 utime($t0, $t0, $dst_mf) or xbail "utime: $!";
108 ok(run_script($cmd), 'clone again +symlinks');
109 ok(-l "$tmpdir/dst/old/a.git", 'symlink created');
110 is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
111 'projects.list does not include symlink by default');
113 $r = $read_manifest->($dst_mf);
114 is_deeply($r, $m, 'updated manifest matches');
116 { # cleanup old projects from projects.list
117 open my $fh, '>>', $dst_pl or xbail $!;
118 print $fh "gone.git\n" or xbail $!;
119 close $fh or xbail $!;
121 utime($t0, $t0, $dst_mf) or xbail "utime: $!";
122 my $rdr = { 2 => \(my $err = '') };
123 ok(run_script($cmd, undef, $rdr), 'clone again for expired gone.git');
124 is(PublicInbox::Git::try_cat($dst_pl), "a.git\nb.git\n",
125 'project list cleaned');
126 like($err, qr/no longer exist.*\bgone\.git\b/s, 'gone.git noted');