about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-01-15 03:00:13 +0000
committerEric Wong <e@80x24.org>2016-04-05 18:58:27 +0000
commitb01b50858cac10ff8cd9722fd5be9bcaf314b83c (patch)
treea92b104a88f3a20aec7923c215720b1c6532b384
parentdd3ff54154f7a771da07c10f500e3033c8ce71bc (diff)
downloadpublic-inbox-b01b50858cac10ff8cd9722fd5be9bcaf314b83c.tar.gz
This should provide a decent landing page for projects.
Alternative README files may be configured with the per-repo
"readme" directive.
-rw-r--r--lib/PublicInbox/Repobrowse.pm46
-rw-r--r--lib/PublicInbox/RepobrowseConfig.pm2
-rw-r--r--lib/PublicInbox/RepobrowseGitSummary.pm102
3 files changed, 130 insertions, 20 deletions
diff --git a/lib/PublicInbox/Repobrowse.pm b/lib/PublicInbox/Repobrowse.pm
index 75dee72f..9e97593b 100644
--- a/lib/PublicInbox/Repobrowse.pm
+++ b/lib/PublicInbox/Repobrowse.pm
@@ -63,33 +63,41 @@ sub run {
         };
 
         my $cmd = shift @extra;
+        my $vcs_lc = $repo_info->{vcs};
+        my $vcs = $VCS{$vcs_lc} or return r404();
+        my $mod;
         if (defined $cmd && length $cmd) {
-                my $vcs_lc = $repo_info->{vcs};
-                my $vcs = $VCS{$vcs_lc} or return r404();
-                my $mod = $CMD{$cmd};
+                $mod = $CMD{$cmd};
                 unless ($mod) {
                         unshift @extra, $cmd;
                         $mod = 'Fallback';
                 }
-                $mod = load_once("PublicInbox::Repobrowse$vcs$mod");
-                $vcs = load_once("PublicInbox::$vcs");
-                $repo_info->{$vcs_lc} ||= $vcs->new($repo_info->{path});
                 $req->{relcmd} = '../' x scalar(@extra);
-                while (@extra && $extra[-1] eq '') {
-                        pop @extra;
-                        ++$req->{tslash};
-                }
-                $req->{expath} = join('/', @extra);
-                my $rv = eval { $mod->new->call($cmd, $req) };
-                $rv || r404();
         } else {
-                $req->{relcmd} = defined $cmd ? ''  : './';
-                summary($req);
+                $mod = 'Summary';
+                $cmd = 'summary';
+                if ($path_info =~ m!/\z!) {
+                        $req->{tslash} = $path_info =~ tr!/!!;
+                        $req->{relcmd} = '';
+                } else {
+                        my @repo = split('/', $repo_path);
+                        if (@repo > 1) {
+                                $req->{relcmd} = "./$repo[-1]/";
+                        } else {
+                                $req->{relcmd} = "/$repo[-1]/";
+                        }
+                }
         }
-}
-
-sub summary {
-        r404();
+        $mod = load_once("PublicInbox::Repobrowse$vcs$mod");
+        $vcs = load_once("PublicInbox::$vcs");
+        $repo_info->{$vcs_lc} ||= $vcs->new($repo_info->{path});
+        while (@extra && $extra[-1] eq '') {
+                pop @extra;
+                ++$req->{tslash};
+        }
+        $req->{expath} = join('/', @extra);
+        my $rv = eval { $mod->new->call($cmd, $req) }; # RepobrowseBase::call
+        $rv || r404();
 }
 
 sub r404 { r(404, 'Not Found') }
diff --git a/lib/PublicInbox/RepobrowseConfig.pm b/lib/PublicInbox/RepobrowseConfig.pm
index 2f780b65..b643f7dc 100644
--- a/lib/PublicInbox/RepobrowseConfig.pm
+++ b/lib/PublicInbox/RepobrowseConfig.pm
@@ -45,7 +45,7 @@ sub lookup {
         $rv->{desc_html} =
                 PublicInbox::Hval->new_oneline($rv->{description})->as_html;
 
-        foreach my $key (qw(publicinbox vcs)) {
+        foreach my $key (qw(publicinbox vcs readme)) {
                 $rv->{$key} = $self->{"repo.$repo_path.$key"};
         }
 
diff --git a/lib/PublicInbox/RepobrowseGitSummary.pm b/lib/PublicInbox/RepobrowseGitSummary.pm
new file mode 100644
index 00000000..65e32b6a
--- /dev/null
+++ b/lib/PublicInbox/RepobrowseGitSummary.pm
@@ -0,0 +1,102 @@
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# The main summary/landing page of a git repository viewer
+package PublicInbox::RepobrowseGitSummary;
+use strict;
+use warnings;
+use PublicInbox::Hval qw(utf8_html);
+use base qw(PublicInbox::RepobrowseBase);
+
+sub call_git_summary {
+        my ($self, $req) = @_;
+        sub {
+                my ($res) = @_; # Plack streaming callback
+                emit_summary($self, $req, $res);
+        }
+}
+
+use constant EACH_REF_FMT => '--format=' .
+                join(' ', map { "%($_)" }
+                qw(refname objecttype objectname creatordate:short subject));
+
+sub emit_summary {
+        my ($self, $req, $res) = @_;
+        my $repo_info = $req->{repo_info};
+        my $git = $repo_info->{git};
+        my $count = 10; # TODO: configurable
+        my $fh;
+
+        # n.b. we would use %(HEAD) in for-each-ref --format if we could
+        # rely on git 1.9.0+, but it's too soon for that in early 2016...
+        chomp(my $head_ref = $git->qx(qw(rev-parse HEAD~0)));
+
+        my $refs = $git->popen(qw(for-each-ref --sort=-creatordate),
+                                EACH_REF_FMT, "--count=$count",
+                                qw(refs/heads/ refs/tags/));
+        $fh = $res->([200, ['Content-Type'=>'text/html; charset=UTF-8']]);
+        # ref names are unpredictable in length and requires tables :<
+        $fh->write($self->html_start($req,
+                                "$repo_info->{path_info}: overview") .
+                        '</pre><table>');
+
+        my $rel = $req->{relcmd};
+        foreach (<$refs>) {
+                my ($ref, $type, $hex, $date, $s) = split(' ', $_, 5);
+                $ref =~ s!\Arefs/(?:heads|tags)/!!;
+                $ref = PublicInbox::Hval->utf8($ref);
+                my $h = $ref->as_html;
+                $ref = $ref->as_href;
+                my $sref;
+                if ($type eq 'tag') {
+                        $h = "<b>$h</b>";
+                        $sref = $ref = $rel . 'tag?h=' . $ref;
+                } elsif ($type eq 'commit') {
+                        $sref = $rel . 'commit?h=' . $ref;
+                        $ref = $rel . 'log?h=' . $ref;
+                } else {
+                        # no point in wasting code to support tagged
+                        # trees/blobs...
+                        next;
+                }
+                chomp $s;
+                my $x = $hex eq $head_ref ? ' (HEAD)' : '';
+                $fh->write(qq(<tr><td><tt><a\nhref="$ref">$h</a>$x</tt></td>) .
+                        qq(<td><tt>$date <a\nhref="$sref">) . utf8_html($s) .
+                        '</a></tt></td></tr>');
+
+        }
+        $fh->write('</table>');
+
+        # some people will use README.md or even README.sh here...
+        my $readme = $repo_info->{readme};
+        defined $readme or $readme = 'README';
+        my $doc = $git->cat_file('HEAD:'.$readme);
+        if (defined $doc) {
+                $fh->write('<pre>' .
+                        readme_path_links($rel, $readme) . " (HEAD)\n\n");
+                $fh->write(utf8_html($$doc));
+                $fh->write('</pre>');
+        }
+        $fh->write('</body></html>');
+        $fh->close;
+}
+
+sub readme_path_links {
+        my ($rel, $readme) = @_;
+        my @path = split(m!/+!, $readme);
+
+        my $s = "tree <a\nhref=\"${rel}tree\">root</a>/";
+        my @t;
+        $s .= join('/', (map {
+                push @t, $_;
+                my $e = PublicInbox::Hval->utf8($_, join('/', @t));
+                my $ep = $e->as_path;
+                my $eh = $e->as_html;
+                $e = "<a\nhref=\"${rel}tree/$ep\">$eh</a>";
+                # bold the last one
+                scalar(@t) == scalar(@path) ? "<b>$e</b>" : $e;
+        } @path));
+}
+
+1;