1 # Copyright (C) 2014-2015 all contributors <meta@public-inbox.org>
2 # License: GPLv2 or later (https://www.gnu.org/licenses/gpl-2.0.txt)
4 # Used to read files from a git repository without excessive forking.
5 # Used in our web interfaces as well as our -nntpd server.
6 # This is based on code in Git.pm which is GPLv2, but modified to avoid
7 # dependence on environment variables for compatibility with mod_perl.
8 # There are also API changes to simplify our usage and data set.
9 package PublicInbox::GitCatFile;
16 my ($class, $git_dir) = @_;
17 bless { git_dir => $git_dir }, $class
22 return if $self->{pid};
23 my ($in_r, $in_w, $out_r, $out_w);
25 pipe($in_r, $in_w) or die "pipe failed: $!\n";
26 pipe($out_r, $out_w) or die "pipe failed: $!\n";
28 my @cmd = ('git', "--git-dir=$self->{git_dir}", qw(cat-file --batch));
30 defined $pid or die "fork failed: $!\n";
32 dup2(fileno($out_r), 0) or die "redirect stdin failed: $!\n";
33 dup2(fileno($in_w), 1) or die "redirect stdout failed: $!\n";
34 exec(@cmd) or die 'exec `' . join(' '). "' failed: $!\n";
36 close $out_r or die "close failed: $!\n";
37 close $in_w or die "close failed: $!\n";
41 $self->{out} = $out_w;
46 my ($self, $object, $sizeref) = @_;
48 $self->_cat_file_begin;
49 print { $self->{out} } $object, "\n" or die "pipe write error: $!\n";
53 $head =~ / missing$/ and return undef;
54 $head =~ /^[0-9a-f]{40} \S+ (\d+)$/ or
55 die "Unexpected result from git cat-file: $head\n";
58 $$sizeref = $size if $sizeref;
59 my $bytes_left = $size;
64 my $read = read($in, $rv, $bytes_left, $offset);
65 defined($read) or die "sysread pipe failed: $!\n";
70 my $read = read($in, my $buf, 1);
71 defined($read) or die "read pipe failed: $!\n";
72 if ($read != 1 || $buf ne "\n") {
73 die "newline missing after blob\n";
80 my $pid = $self->{pid} or return;
82 foreach my $f (qw(in out)) {