From d9563ea5516e8e786debf223e10ec11695aee9d7 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 9 Feb 2017 01:37:03 +0000 Subject: repobrowse: shorten internal names We'll still be keeping "repobrowse" for the public API for use with .psgi files, but shortening the name means less typing and we may have command-line tools, too. --- lib/PublicInbox/RepoGitAtom.pm | 169 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 lib/PublicInbox/RepoGitAtom.pm (limited to 'lib/PublicInbox/RepoGitAtom.pm') diff --git a/lib/PublicInbox/RepoGitAtom.pm b/lib/PublicInbox/RepoGitAtom.pm new file mode 100644 index 00000000..a9f40126 --- /dev/null +++ b/lib/PublicInbox/RepoGitAtom.pm @@ -0,0 +1,169 @@ +# Copyright (C) 2016 all contributors +# License: AGPL-3.0+ + +# show log as an Atom feed +package PublicInbox::RepoGitAtom; +use strict; +use warnings; +use PublicInbox::Hval qw(utf8_html); +use base qw(PublicInbox::RepoBase); +use PublicInbox::Qspawn; + +use constant DATEFMT => '%Y-%m-%dT%H:%M:%SZ'; +use constant STATES => qw(H ct an ae at s b); +use constant STATE_BODY => (scalar(STATES) - 1); +my $ATOM_FMT = '--pretty=tformat:'. + join('%n', map { "%$_" } STATES).'%x00'; +use POSIX qw(strftime); + +sub repo_root_url { + my ($self, $req) = @_; + my $env = $req->{env}; + my $uri = $env->{REQUEST_URI}; + $uri =~ s/\?.+\z//; # no query string + my @uri = split(m!/+!, $uri); + my @extra = @{$req->{extra}}; + while (@uri && @extra && $uri[-1] eq $extra[-1]) { + pop @uri; + pop @extra; + } + pop @uri if $uri[-1] eq 'atom'; # warn if not equal? + PublicInbox::Repobrowse::base_url($env) . join('/', @uri); +} + +sub flush_hdr ($$$) { + my ($dst, $hdr, $url) = @_; + $$dst .= ''; + $$dst .= utf8_html($hdr->{'s'}); # commit subject + $$dst .= ''; + $$dst .= strftime(DATEFMT, gmtime($hdr->{ct})); + $$dst .= ''; + $$dst .= utf8_html($hdr->{an}); + $$dst .= ''; + $$dst .= utf8_html($hdr->{ae}); + $$dst .= ''; + $$dst .= strftime(DATEFMT, gmtime($hdr->{at})); + $$dst .= ''; + $$dst .= qq(); + $$dst .= $H; + $$dst .= qq(); + + $$dst .= qq(); + $$dst .= qq(); + undef +} + +sub git_atom_sed ($$) { + my ($self, $req) = @_; + my $buf = ''; + my $state = 0; + my $rel = $req->{relcmd}; + my $repo_info = $req->{repo_info}; + my $title = join('/', $repo_info->{repo}, @{$req->{extra}}); + $title = utf8_html("$title, branch $req->{q}->{h}"); + my $url = repo_root_url($self, $req); + my $hdr = {}; + $req->{axml} = qq(\n) . + qq() . + qq($title) . + qq($repo_info->{desc_html}) . + qq(); + my ($plinks, $id, $ai); + my $end = ''; + my $blines; + sub { + my $dst; + # $_[0] == scalar buffer, undef means EOF from "git log" + $dst = delete $req->{axml} || ''; + my @tmp; + if (defined $_[0]) { + $buf .= $_[0]; + @tmp = split(/\n/, $buf, -1); + $buf = @tmp ? pop(@tmp) : ''; + } else { + @tmp = split(/\n/, $buf, -1); + $buf = ''; + $end = ''; + } + + foreach my $l (@tmp) { + if ($state != STATE_BODY) { + $hdr->{((STATES)[$state])} = $l; + if (++$state == STATE_BODY) { + flush_hdr(\$dst, $hdr, $url); + $hdr = {}; + $blines = 0; + } + next; + } + if ($l eq "\0") { + $dst .= qq(); + $state = 0; + } else { + $dst .= "\n" if $blines++; + $dst .= utf8_html($l); + } + } + $dst .= $end; + } +} + +sub git_atom_cb { + my ($self, $req) = @_; + sub { + my ($r) = @_; + my $env = $req->{env}; + if (!defined $r) { + my $git = $req->{repo_info}->{git}; + return [ 400, [ 'Content-Type', 'text/plain' ], + [ $git->err ] ]; + } + $env->{'qspawn.filter'} = git_atom_sed($self, $req); + [ 200, [ 'Content-Type', 'application/atom+xml' ] ]; + } +} + +sub call_git_atom { + my ($self, $req) = @_; + my $repo_info = $req->{repo_info}; + my $max = $repo_info->{max_commit_count} || 10; + $max = int($max); + $max = 50 if $max == 0; + + my $git = $repo_info->{git}; + my $env = $req->{env}; + my $q =$req->{'q'} = PublicInbox::RepoGitQuery->new($env); + my $h = $q->{h}; + my $read_log = sub { + my $cmd = $git->cmd(qw(log --no-notes --no-color + --abbrev-commit), $git->abbrev, + $ATOM_FMT, "-$max", $h, '--'); + my $expath = $req->{expath}; + push @$cmd, $expath if $expath ne ''; + my $rdr = { 2 => $git->err_begin }; + my $qsp = PublicInbox::Qspawn->new($cmd, undef, undef, $rdr); + $qsp->psgi_return($env, undef, git_atom_cb($self, $req)); + }; + + sub { + $env->{'qspawn.response'} = $_[0]; + return $read_log->() if $h ne ''; + + my $cmd = $git->cmd(qw(symbolic-ref --short HEAD)); + my $rdr = { 2 => $git->err_begin }; + my $qsp = PublicInbox::Qspawn->new($cmd, undef, undef, $rdr); + $qsp->psgi_qx($env, undef, sub { + chomp($h = ${$_[0]}); + $read_log->(); + }) + } +} + +1; -- cgit v1.2.3-24-ge0c7