diff options
author | Eric Wong <e@80x24.org> | 2016-12-13 21:56:39 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2016-12-14 00:22:55 +0000 |
commit | 00488f0cfe9f81d04cd65d09ea783e860c937401 (patch) | |
tree | 24e4d9282d5e7098fc6cbdcc9d5615c46513661f /lib/PublicInbox/Git.pm | |
parent | f9d4f28d9761011d3c7ffad9e2c9d1e54b65c519 (diff) | |
parent | 6cdb0221d18b2caed4d0caebf7c20d6eb159497d (diff) | |
download | public-inbox-00488f0cfe9f81d04cd65d09ea783e860c937401.tar.gz |
* origin/repobrowse: (98 commits) t/repobrowse_git_httpd.t: ensure signature exists for split t/repobrowse_git_tree.t: fix test for lack of bold repobrowse: fix alignment of gitlink entries repobrowse: show invalid type for tree views repobrowse: do not bold directory names in tree view repobrowse: reduce checks for response fh repobrowse: larger, short-lived buffer for reading patches repobrowse: reduce risk of callback reference cycles repobrowse: snapshot support for cgit compatibility test: disable warning for Plack::Test::Impl repobrowse: avoid confusing linkification for "diff" repobrowse: git commit view uses pi-httpd.async repobrowse: more consistent variable naming for /commit/ repobrowse: show roughly equivalent "diff-tree" invocation repobrowse: reduce local variables for state management repobrowse: summary handles multiple README types repobrowse: remove bold decorations from diff view repobrowse: common git diff parsing code repobrowse: implement diff view for compatibility examples/repobrowse.psgi: disable Chunked response by default ...
Diffstat (limited to 'lib/PublicInbox/Git.pm')
-rw-r--r-- | lib/PublicInbox/Git.pm | 89 |
1 files changed, 67 insertions, 22 deletions
diff --git a/lib/PublicInbox/Git.pm b/lib/PublicInbox/Git.pm index 59c27470..dee027a3 100644 --- a/lib/PublicInbox/Git.pm +++ b/lib/PublicInbox/Git.pm @@ -12,10 +12,35 @@ use warnings; use POSIX qw(dup2); require IO::Handle; use PublicInbox::Spawn qw(spawn popen_rd); +use IO::File; +use Fcntl qw(:seek); + +# Documentation/SubmittingPatches recommends 12 (Linux v4.4) +my $abbrev = `git config core.abbrev` || 12; + +sub abbrev { "--abbrev=$abbrev" } sub new { my ($class, $git_dir) = @_; - bless { git_dir => $git_dir }, $class + bless { git_dir => $git_dir, err => IO::File->new_tmpfile }, $class +} + +sub err_begin ($) { + my $err = $_[0]->{err}; + sysseek($err, 0, SEEK_SET) or die "sysseek failed: $!"; + truncate($err, 0) or die "truncate failed: $!"; + my $ret = fileno($err); + defined $ret or die "fileno failed: $!"; + $ret; +} + +sub err ($) { + my $err = $_[0]->{err}; + sysseek($err, 0, SEEK_SET) or die "sysseek failed: $!"; + defined(sysread($err, my $buf, -s $err)) or die "sysread failed: $!"; + sysseek($err, 0, SEEK_SET) or die "sysseek failed: $!"; + truncate($err, 0) or die "truncate failed: $!"; + $buf; } sub _bidi_pipe { @@ -36,20 +61,43 @@ sub _bidi_pipe { $self->{$in} = $in_r; } -sub cat_file { - my ($self, $obj, $ref) = @_; - - batch_prepare($self); +sub cat_file_begin { + my ($self, $obj) = @_; + $self->_bidi_pipe(qw(--batch in out pid)); $self->{out}->print($obj, "\n") or fail($self, "write error: $!"); my $in = $self->{in}; local $/ = "\n"; my $head = $in->getline; $head =~ / missing$/ and return undef; - $head =~ /^[0-9a-f]{40} \S+ (\d+)$/ or + $head =~ /^([0-9a-f]{40}) (\S+) (\d+)$/ or fail($self, "Unexpected result from git cat-file: $head"); - my $size = $1; + ($in, $1, $2, $3); +} + +sub cat_file_finish { + my ($self, $left) = @_; + my $max = 8192; + my $in = $self->{in}; + my $buf; + while ($left > 0) { + my $r = read($in, $buf, $left > $max ? $max : $left); + defined($r) or fail($self, "read failed: $!"); + $r == 0 and fail($self, 'exited unexpectedly'); + $left -= $r; + } + + my $r = read($in, $buf, 1); + defined($r) or fail($self, "read failed: $!"); + fail($self, 'newline missing after blob') if ($r != 1 || $buf ne "\n"); +} + +sub cat_file { + my ($self, $obj, $ref) = @_; + + my ($in, $hex, $type, $size) = $self->cat_file_begin($obj); + return unless $in; my $ref_type = $ref ? ref($ref) : ''; my $rv; @@ -58,16 +106,8 @@ sub cat_file { my $cb_err; if ($ref_type eq 'CODE') { - $rv = eval { $ref->($in, \$left) }; + $rv = eval { $ref->($in, \$left, $type, $hex) }; $cb_err = $@; - # drain the rest - my $max = 8192; - while ($left > 0) { - my $r = read($in, my $x, $left > $max ? $max : $left); - defined($r) or fail($self, "read failed: $!"); - $r == 0 and fail($self, 'exited unexpectedly'); - $left -= $r; - } } else { my $offset = 0; my $buf = ''; @@ -80,10 +120,7 @@ sub cat_file { } $rv = \$buf; } - - my $r = read($in, my $buf, 1); - defined($r) or fail($self, "read failed: $!"); - fail($self, 'newline missing after blob') if ($r != 1 || $buf ne "\n"); + $self->cat_file_finish($left); die $cb_err if $cb_err; $rv; @@ -119,8 +156,16 @@ sub fail { sub popen { my ($self, @cmd) = @_; - @cmd = ('git', "--git-dir=$self->{git_dir}", @cmd); - popen_rd(\@cmd); + my $cmd = [ 'git', "--git-dir=$self->{git_dir}" ]; + my ($env, $opt); + if (ref $cmd[0]) { + push @$cmd, @{$cmd[0]}; + $env = $cmd[1]; + $opt = $cmd[2]; + } else { + push @$cmd, @cmd; + } + popen_rd($cmd, $env, $opt); } sub qx { |