diff options
Diffstat (limited to 'lib/PublicInbox/RepoBrowse.pm')
-rw-r--r-- | lib/PublicInbox/RepoBrowse.pm | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/PublicInbox/RepoBrowse.pm b/lib/PublicInbox/RepoBrowse.pm new file mode 100644 index 00000000..5865d65d --- /dev/null +++ b/lib/PublicInbox/RepoBrowse.pm @@ -0,0 +1,85 @@ +# Copyright (C) 2015 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> + +# Version control system (VCS) repository viewer like cgit or gitweb, +# but with optional public-inbox archive integration. +# This uses cgit-compatible PATH_INFO URLs. +# This may be expanded to support other Free Software VCSes such as +# Subversion and Mercurial, so not just git +# +# Same web design principles as PublicInbox::WWW for supporting the +# lowest common denominators (see bottom of Documentation/design_www.txt) +# +# This allows an M:N relationship between "normal" repos for project +# and public-inbox (ssoma) git repositories where N may be zero. +# In other words, RepoBrowse must work for repositories without +# any public-inbox at all; or with multiple public-inboxes. +# And the rest of public-inbox will always work without a "normal" +# code repo for the project. + +package PublicInbox::RepoBrowse; +use strict; +use warnings; +use URI::Escape qw(uri_escape_utf8 uri_unescape); +use PublicInbox::RepoConfig; + +my %CMD = map { lc($_) => $_ } qw(Log Commit); + +sub new { + my ($class, $file) = @_; + bless { rconfig => PublicInbox::RepoConfig->new($file) }, $class; +} + +# simple response for errors +sub r { [ $_[0], ['Content-Type' => 'text/plain'], [ join(' ', @_, "\n") ] ] } + +sub run { + my ($self, $cgi, $method) = @_; + return r(405, 'Method Not Allowed') if ($method !~ /\AGET|HEAD\z/); + + # URL syntax: / repo [ / cmd [ / path ] ] + # cmd: log | commit | diff | tree | view | blob | snapshot + # repo and path may both contain '/' + my $rconfig = $self->{rconfig}; + my (undef, $repo_path, @extra) = split(m{/+}, $cgi->path_info, -1); + + return r404() unless $repo_path; + my $repo_info; + until ($repo_info = $rconfig->lookup($repo_path)) { + my $p = shift @extra or last; + $repo_path .= "/$p"; + } + return r404() unless $repo_info; + + my $req = { + repo_info => $repo_info, + path => \@extra, + cgi => $cgi, + rconfig => $rconfig, + }; + + my $cmd = shift @extra; + if (defined $cmd && length $cmd) { + my $mod = $CMD{$cmd}; + return r404() unless defined $mod; + if (index($mod, ':') < 0) { + $mod = "PublicInbox::RepoBrowse$mod"; + eval "require $mod"; + $CMD{$cmd} = $mod unless $@; + } + $req->{relcmd} = '../' x scalar(@extra); + my $rv = eval { $mod->new->call($req) }; + $rv || r404(); + } else { + $req->{relcmd} = defined $cmd ? '' : './'; + summary($req); + } +} + +sub summary { + r404(); +} + +sub r404 { r(404, 'Not Found') } + +1; |