This commit is contained in:
anon 2025-08-20 23:17:52 +02:00
commit 9e5210b13f
6 changed files with 129 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.sqlite3
config.pl
git/*
!git/public/.gitkeep
!git/private/.gitkeep

6
config.pl.example Normal file
View File

@ -0,0 +1,6 @@
# always assume anything to do with files is from project root
use constant GIT_ROOT => 'git'; # directory containing all browsable $users/$repositories
use constant DB_FILE => 'gorillanest.sqlite3'; # sqlite3 database file location
use constant TEMPLATE_ROOT => 'template'; # template directory
use constant USER_REPOSITORY => qr{^/([a-zA-Z0-9_.]+)(?:/([a-zA-Z0-9_.]+))?}; # $1 = username, $2 = repository fullname
1;

0
git/private/.gitkeep Normal file
View File

0
git/public/.gitkeep Normal file
View File

121
gorillanest.pl Executable file
View File

@ -0,0 +1,121 @@
#!/usr/bin/env perl
use strict;
use warnings;
use CGI;
use FCGI;
use Switch::Back;
use Syntax::Keyword::Try;
use Template;
use URI::Escape;
use Cwd;
use Data::Dumper;
use Git::Repository;
use lib '.';
BEGIN { require 'config.pl'; }
sub info {
warn join(' ', @_);
}
# significant dirs only
sub GN::directories {
my $root = $_[0];
opendir my $dir, $root or die "Cannot open directory: $!";
my @directories;
my %drop = (
'.' => 0,
'..' => 0,
);
foreach (readdir $dir) {
push(@directories, $_) if (-d join('/', $_[0], $_) && ($drop{$_} // 1));
}
closedir $dir;
return \@directories;
}
# probably should output all repos recursively, currently just outputs list of users
sub GN::index { # /
my ($root, $dataref) = @_;
my %data = %$dataref;
my @directories = map { my $i = $_; map { join('/', $i, $_) } @{GN::directories(join('/', $root, $i))} } @{GN::directories($root)};
$data{directories} = \@directories;
if ($data{directories}) { $data{found} = 1; }
return \%data;
}
sub GN::user { # /$username/
my ($root, $dataref) = @_;
my %data = %$dataref;
my @directories = @{GN::directories(join('/', $root, $data{username}))};
$data{directories} = \@directories;
if ($data{directories}) { $data{found} = 1; }
return \%data;
}
sub GN::repository { # /$username/$repository
my ($root, $dataref) = @_;
my %data = %$dataref;
$data{found} = 0;
return \%data;
}
sub GN::main {
open STDERR, '>', '/tmp/gorillanest.log' or die "You Will Never Ever See This Message Hopefully: $!";
my $sock = FCGI::OpenSocket('/tmp/gorillanest.socket', 100);
try {
my $root = GIT_ROOT;
my $dbfile = DB_FILE;
my %data = (
found => 0,
access => 0,
);
my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $sock);
my $template = Template->new({INCLUDE_PATH => TEMPLATE_ROOT});
my $head = 0;
my $a_template;
while($request->Accept() >= 0) {
$data{access} += 1;
my $cgi = CGI->new;
my %header = (
-Content_Type => 'text/html',
-charset => 'UTF-8',
);
my $method = $ENV{'REQUEST_METHOD'} || '';
my $uri = $ENV{'REQUEST_URI'} || '/';
if ($method eq 'HEAD') {
$head = 1;
} elsif ($method eq 'GET') {
($data{username}, $data{repository}) = $uri =~ USER_REPOSITORY;
info("name:", $data{username} || '', "repo:", $data{repository} || '');
if ($uri eq '/') {
%data = %{GN::index($root, \%data)};
$a_template = "index.tt";
} elsif ($data{repository}) {
%data = %{GN::repository($root, \%data)};
$a_template = "repository.tt";
} elsif ($data{username}) {
%data = %{GN::user($root, \%data)};
$a_template = "index_user.tt";
}
if (!$data{found}) {
$header{-status} = '404 Not Found';
$a_template = "404.tt";
}
print $cgi->header(%header);
if ($head) { $head = 0; continue; }
$template->process($a_template, \%data) or info("Template: " . $template->error());
} else {
$header{-status} = '405 Method Not Allowed';
print $cgi->header(%header);
}
}
} catch ($error) {
info("Crashed: $error");
}
FCGI::CloseSocket($sock);
}
GN::main();

View File

@ -6,6 +6,7 @@
<h1>[% title %]</h1>
<h2>[% description %]</h2>
<ul>[% FOR i IN directories %]<li><a href="/[% i %]">/[% i %]</a></li>[% END %]</ul>
<p>one million [% access %] xolatile's</p>
</body>
[% INCLUDE foot.tt %]
</html>