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)
3 # This is based on code in Git.pm which is GPLv2, but modified to avoid
4 # dependence on environment variables for compatibility with mod_perl.
5 # There are also API changes to simplify our usage and data set.
6 package PublicInbox::GitCatFile;
13 my ($class, $git_dir) = @_;
14 bless { git_dir => $git_dir }, $class;
19 return if $self->{pid};
20 my ($in_r, $in_w, $out_r, $out_w);
22 pipe($in_r, $in_w) or die "pipe failed: $!\n";
23 pipe($out_r, $out_w) or die "pipe failed: $!\n";
25 my @cmd = ('git', "--git-dir=$self->{git_dir}", qw(cat-file --batch));
27 defined $pid or die "fork failed: $!\n";
29 dup2(fileno($out_r), 0) or die "redirect stdin failed: $!\n";
30 dup2(fileno($in_w), 1) or die "redirect stdout failed: $!\n";
31 exec(@cmd) or die 'exec `' . join(' '). "' failed: $!\n";
33 close $out_r or die "close failed: $!\n";
34 close $in_w or die "close failed: $!\n";
38 $self->{out} = $out_w;
43 my ($self, $object, $sizeref) = @_;
45 $self->_cat_file_begin;
46 print { $self->{out} } $object, "\n" or die "pipe write error: $!\n";
50 $head =~ / missing$/ and return undef;
51 $head =~ /^[0-9a-f]{40} \S+ (\d+)$/ or
52 die "Unexpected result from git cat-file: $head\n";
55 $$sizeref = $size if $sizeref;
56 my $bytes_left = $size;
61 my $read = read($in, $rv, $bytes_left, $offset);
62 defined($read) or die "sysread pipe failed: $!\n";
67 my $read = read($in, my $buf, 1);
68 defined($read) or die "read pipe failed: $!\n";
69 if ($read != 1 || $buf ne "\n") {
70 die "newline missing after blob\n";
77 my $pid = $self->{pid} or return;
79 foreach my $f (qw(in out)) {