Sometimes; people like to advertise projects and group them.
Of course, "-hidden" is a valid group for projects which do
not want to be advertised.
[ "Redirecting to $url\n" ] ]
}
+sub root_index {
+ my ($self) = @_;
+ my $mod = load_once('PublicInbox::RepobrowseRoot');
+ $mod->new->call($self->{rconfig}); # RepobrowseRoot::call
+}
+
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 (@extra) may both contain '/'
- my $rconfig = $self->{rconfig};
my $path_info = uri_unescape($cgi->path_info);
my (undef, $repo_path, @extra) = split(m{/+}, $path_info, -1);
- return r404() unless $repo_path;
+ return $self->root_index($self) unless length($repo_path);
+
+ my $rconfig = $self->{rconfig}; # RepobrowseConfig
my $repo_info;
until ($repo_info = $rconfig->lookup($repo_path)) {
my $p = shift @extra or last;
if ($path_info =~ m!/\z!) {
$tslash = $path_info =~ tr!/!!;
} else {
- my @repo = split('/', $repo_path);
- if (@repo > 1) {
- $req->{relcmd} = "./$repo[-1]/";
- } else {
- $req->{relcmd} = "/$repo[-1]/";
- }
+ my @x = split('/', $repo_path);
+ $req->{relcmd} = @x > 1 ? "./$x[-1]/" : "/$x[-1]/";
}
}
while (@extra && $extra[-1] eq '') {
++$tslash;
}
- if ($tslash && $path_info ne '/' && $NO_TSLASH{$mod}) {
- return no_tslash($cgi);
- }
+ return no_tslash($cgi) if ($tslash && $NO_TSLASH{$mod});
$req->{tslash} = $tslash;
$mod = load_once("PublicInbox::Repobrowse$vcs$mod");
$file = default_file() unless defined($file);
my $self = bless PublicInbox::Config::git_config_dump($file), $class;
$self->{-cache} = {};
+ # for root
+ $self->{-groups} = { -hidden => [], -none => [] };
$self;
}
my $path = $self->{"repo.$repo_path.path"};
(defined $path && -d $path) or return;
$rv->{path} = $path;
- $rv->{path_info} = $repo_path;
+ $rv->{repo} = $repo_path;
+ # gitweb compatibility
foreach my $key (qw(description cloneurl)) {
$rv->{$key} = try_cat("$path/$key");
}
$rv->{desc_html} =
PublicInbox::Hval->new_oneline($rv->{description})->as_html;
- foreach my $key (qw(publicinbox vcs readme)) {
+ foreach my $key (qw(publicinbox vcs readme group)) {
$rv->{$key} = $self->{"repo.$repo_path.$key"};
}
+ my $g = $rv->{group};
+ defined $g or $g = '-none';
+ if (ref($g) eq 'ARRAY') {
+ push @{$self->{-groups}->{$_} ||= []}, $repo_path foreach @$g;
+ } else {
+ push @{$self->{-groups}->{$g} ||= []}, $repo_path;
+ }
+
# of course git is the default VCS
$rv->{vcs} ||= 'git';
$self->{-cache}->{$repo_path} = $rv;
sub {
my ($res) = @_; # Plack callback
my $fh = $res->([200, ['Content-Type'=>'text/html']]);
- my $title = utf8_html("log: $repo_info->{path_info} ($h)");
+ my $title = "log: $repo_info->{repo} ".utf8_html("($h)");
$fh->write($self->html_start($req, $title));
git_log_stream($req, $q, $log, $fh, $git);
$fh->close;
$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") .
+ "$repo_info->{repo}: overview") .
'</pre><table>');
my $rel = $req->{relcmd};
# tag names are unpredictable in length and requires tables :<
$fh->write($self->html_start($req,
- "$repo_info->{path_info}: tag list") .
+ "$repo_info->{repo}: tag list") .
'</pre><table><tr>' .
join('', map { "<th><tt>$_</tt></th>" } qw(tag subject date)).
'</tr>');
my $obj_link = qq(<a\nhref="$rel$cmd?id=$hex">$label</a>\n);
$fh->write($self->html_start($req,
- "$repo_info->{path_info}: ref: $h") .
+ "$repo_info->{repo}: ref: $h") .
"\n\n <b>$h</b> (lightweight tag)\nobject $obj_link\n");
}
--- /dev/null
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# displays the root '/' where all the projects lie
+package PublicInbox::RepobrowseRoot;
+use strict;
+use warnings;
+use base qw(PublicInbox::RepobrowseBase);
+use PublicInbox::Hval qw(utf8_html);
+
+sub call {
+ my ($self, $rconfig) = @_;
+ sub {
+ my ($res) = @_; # PSGI callback
+ my @h = ('Content-Type', 'text/html; charset=UTF-8');
+ my $fh = $res->([200, \@h]);
+ repobrowse_index($fh, $rconfig);
+ $fh->close;
+ }
+}
+
+sub repobrowse_index {
+ my ($fh, $rconfig) = @_;
+ my $title = 'repobrowse index';
+ $fh->write("<html><head><title>$title</title>" .
+ PublicInbox::Hval::STYLE .
+ "</head><body><pre><b>$title</b>");
+
+ # preload all groups
+ foreach my $k (sort keys %$rconfig) {
+ $k =~ /\Arepo\.(.+)\.path\z/ or next;
+ my $repo_path = $1;
+ $rconfig->lookup($repo_path); # insert into groups
+ }
+
+ my $groups = $rconfig->{-groups};
+ if (scalar(keys %$groups) > 2) { # default has '-none' + '-hidden'
+ $fh->write("\n\n<b>uncategorized</b></pre>".
+ "<table\nsummary=repoindex>");
+ } else {
+ $fh->write("</pre><table\nsummary=repoindex>");
+ }
+ foreach my $repo_path (sort @{$groups->{-none}}) {
+ my $r = $rconfig->lookup($repo_path);
+ my $p = PublicInbox::Hval->utf8($r->{repo});
+ my $l = $p->as_html;
+ $p = $p->as_path;
+ $fh->write(qq(<tr><td><tt><a\nhref="$p">$l</a></tt></td>) .
+ "<td><tt> $r->{desc_html}</tt></td></tr>");
+ }
+
+ foreach my $group (keys %$groups) {
+ next if $group =~ /\A-(?:none|hidden)\z/;
+ my $g = utf8_html($group);
+ $fh->write("<tr><td><pre> </pre></td></tr>".
+ "<tr><td><pre><b>$g</b></pre></tr>");
+ foreach my $repo_path (sort @{$groups->{$group}}) {
+ my $r = $rconfig->lookup($repo_path);
+ my $p = PublicInbox::Hval->utf8($r->{repo});
+ my $l = $p->as_html;
+ $p = $p->as_path;
+ $fh->write('<tr><td><tt> ' .
+ qq(<a\nhref="$p">$l</a></tt></td>) .
+ "<td><tt> $r->{desc_html}</tt></td></tr>");
+ }
+ }
+
+ $fh->write('</table></body></html>');
+}
+
+1;