X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=bin%2Flocal-debbugs;h=482592344c5b21503af0a7f6185cc07c10eef777;hb=1c4ce01f78b112c2247a08f1a0dc9efb5ab3adca;hp=bb9378373490f75e3f6fcf9f91539a55ed4035ee;hpb=0620f287779eb57cbbf7c6f7bf29a752ffbd51f2;p=debbugs.git diff --git a/bin/local-debbugs b/bin/local-debbugs index bb93783..4825923 100755 --- a/bin/local-debbugs +++ b/bin/local-debbugs @@ -8,7 +8,7 @@ use warnings; use strict; -use Getopt::Long; +use Getopt::Long qw(:config no_ignore_case); use Pod::Usage; =head1 NAME @@ -17,7 +17,7 @@ local-debbugs - use a local mirror of debbugs =head1 SYNOPSIS - [options] + local-debbugs [options] Options: --mirror, -M update local mirror @@ -39,19 +39,19 @@ Update the local mirror of debbugs bugs =item B<--daemon, -D> Start up the daemon on the configured local port to serve bugs which -have been previously retried +have been previously retrieved. =item B<--search, -S> Cause the running daemon to show the pkgreport.cgi page corresponding -to the search by invoking sensible-browser and an appropriate url +to the search by invoking sensible-browser and an appropriate url. =item B<--show, -s> Cause the running daemon to show the bugreport.cgi page corresponding -to the bug by invoking sensible-browser and an appropriate url +to the bug by invoking sensible-browser and an appropriate url. -=item B<--port,-p> +=item B<--port, -p> The port that the daemon is running on (or will be running on.) @@ -63,9 +63,20 @@ the configuration file, or 8080 if nothing is set. File which contains the set of bugs to get. Defaults to ~/.debbugs/bugs_to_get +=item B<--bug-site> + +Hostname for a site which is running a debbugs install. +Defaults to bugs.debian.org + +=item B<--bug-mirror> + +Hostname for a site which is running an rsyncable mirror of the +debbugs install above. +Defaults to bugs-mirror.debian.org + =item B<--debug, -d> -Debug verbosity. (Default 0) +Debug verbosity. =item B<--help, -h> @@ -79,6 +90,21 @@ Display this manual. =head1 EXAMPLES +=over + +=item Update the local mirror + + local-debbugs --mirror + +=item Start up the local-debbugs daemon + + local-debbugs --daemon + +=item Search for bugs with severity serious + + local-debbugs --search severity:serious + +=back =cut @@ -87,35 +113,66 @@ use vars qw($DEBUG); use User; use Config::Simple; +use File::Basename qw(dirname); use File::Temp qw(tempdir); use Params::Validate qw(validate_with :types); +use POSIX 'setsid'; +use SOAP::Lite; +use IPC::Run; +use IO::File; +use File::Path; +use File::Spec; my %options = (debug => 0, help => 0, man => 0, verbose => 0, quiet => 0, + detach => 1, + git_mode => -d (dirname(__FILE__).'/../.git') ? 1 : 0, + bug_site => 'bugs.debian.org', + bug_mirror => 'bugs-mirror.debian.org', ); my %option_defaults = (port => 8080, debbugs_config => User->Home.'/.debbugs/debbugs_config', - mirror_location => User->Home.'/.debbugs/mirror/', + mirror_location => User->Home.'/.debbugs/mirror', bugs_to_get => User->Home.'/.debbugs/bugs_to_get', ); GetOptions(\%options, - 'daemon|D','show|s','search|select|S','mirror|M', + 'daemon|D','show|s','search|select|S','mirror|M', 'stop|exit|quit', + 'detach!', + 'css=s','cgi_bin|cgi-bin|cgi=s', 'verbose|v+','quiet|q+', + 'bug_site|bug-site=s', + 'bug_mirror|bug-mirror=s', 'debug|d+','help|h|?','man|m'); +if ($options{git_mode}) { + my $base_dir = dirname(File::Spec->rel2abs(dirname(__FILE__))); + $options{cgi_bin} = "$base_dir/cgi" unless defined $options{cgi_bin}; + $options{css} = "$base_dir/html/bugs.css" unless defined $options{css}; + $options{template_dir} = "$base_dir/templates"; + $options{base_dir} = $base_dir; + eval "use lib '$options{base_dir}'"; +} else { + $options{cgi_bin} = '/var/lib/debbugs/www/cgi'; + $options{css} = '/var/lib/debbugs/www/bugs.css'; + $options{template_dir} = "/usr/share/debbugs/templates"; +} + +eval "use Debbugs::Common qw(checkpid lockpid get_hashname)"; +eval "use Debbugs::Mail qw(get_addresses)"; + pod2usage() if $options{help}; pod2usage({verbose=>2}) if $options{man}; $DEBUG = $options{debug}; my @USAGE_ERRORS; -if (1 != scalar @options{qw(daemon show search mirror)}) { - push @USAGE_ERRORS,"You must pass one (and only one) of --daemon --show --search or --mirror"; +if (1 != grep {exists $options{$_}} qw(daemon show search mirror stop)) { + push @USAGE_ERRORS,"You must pass one (and only one) of --daemon --show --search --mirror or --stop"; } $options{verbose} = $options{verbose} - $options{quiet}; @@ -126,37 +183,196 @@ pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS; local_config(\%options); +mkpath($options{mirror_location}); + if ($options{daemon}) { # daemonize, do stuff + my $pid = checkpid($options{mirror_location}.'/local-debbugs.pid'); + if (defined $pid and $pid != 0) { + print STDERR "Unable to start daemon; it's already running\n"; + exit 1; + } + if (-e $options{mirror_location}.'/local-debbugs.pid' and + not defined $pid) { + print STDERR "Unable to determine if daemon is running: $!\n"; + exit 1; + } + my $conf = IO::File->new($options{mirror_location}.'/debbugs_config_local','w') or + die "Unable to open $options{mirror_location}/debbugs_config_local for writing: $!"; + print {$conf} <<"EOF"; +\$gConfigDir = "$options{mirror_location}"; +\$gSpoolDir = "$options{mirror_location}"; +\$gTemplateDir = "$options{template_dir}"; +\$gWebHost = 'localhost:$options{port}'; +\$gPackageSource = ''; +\$gPseudoDescFile = ''; +\$gPseudoMaintFile = ''; +\$gMaintainerFile = ''; +\$gMaintainerFileOverride = ''; +\$config{source_maintainer_file} = ''; +\$config{source_maintainer_file_override} = ''; +\$gProject = 'Local Debbugs'; +1; +EOF + close $conf; + $ENV{DEBBUGS_CONFIG_FILE} = $options{mirror_location}.'/debbugs_config_local'; + # ok, now lets daemonize + + # XXX make sure that all paths have been turned into absolute + # paths + chdir '/' or die "Can't chdir to /: $!"; + # allow us not to detach for debugging + if ($options{detach}) { + open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; + open STDOUT, '>/dev/null' + or die "Can't write to /dev/null: $!"; + defined(my $pid = fork) or die "Can't fork: $!"; + exit if $pid; + setsid or die "Can't start a new session: $!"; + open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; + } + lockpid($options{mirror_location}.'/local-debbugs.pid') or + die "Unable to deal with the pidfile"; + # this is the subclass of HTTP::Server::Simple::CGI which handles + # the "hard" bits of actually running a tiny webserver for us + { + package local_debbugs::server; + use IO::File; + use HTTP::Server::Simple; + use File::Basename qw(dirname); + use base qw(HTTP::Server::Simple::CGI HTTP::Server::Simple::CGI::Environment); + + sub net_server { + return 'Net::Server::Fork'; + } + + sub redirect { + my ($cgi,$url) = @_; + print "HTTP/1.1 302 Found\r\n"; + print "Location: $url\r\n"; + } + + # here we want to call cgi-bin/pkgreport or cgi-bin/bugreport + sub handle_request { + my ($self,$cgi) = @_; + + $ENV{DEBBUGS_CONFIG_FILE} = $options{mirror_location}.'/debbugs_config_local'; + my $base_uri = 'http://'.$cgi->virtual_host; + if ($cgi->virtual_port ne 80) { + $base_uri .= ':'.$cgi->virtual_port; + } + my $path = $cgi->path_info(); + # RewriteRule ^/[[:space:]]*#?([[:digit:]][[:digit:]][[:digit:]]+)([;&].+)?$ /cgi-bin/bugreport.cgi?bug=$1$2 [L,R,NE] + if ($path =~ m{^/?\s*\#?(\d+)((?:[;&].+)?)$}) { + redirect($cgi,$base_uri."/cgi-bin/bugreport.cgi?bug=$1$2"); + } + # RewriteRule ^/[Ff][Rr][Oo][Mm]:([^/]+\@.+)$ /cgi-bin/pkgreport.cgi?submitter=$1 [L,R,NE] + elsif ($path =~ m{^/?\s*from:([^/]+\@.+)$}i) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?submitter=$1"); + } + # RewriteRule ^/([^/]+\@.+)$ /cgi-bin/pkgreport.cgi?maint=$1 [L,R,NE] + elsif ($path =~ m{^/?\s*([^/]+\@.+)$}i) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?maint=$1"); + } + # RewriteRule ^/mbox:([[:digit:]][[:digit:]][[:digit:]]+)([;&].+)?$ /cgi-bin/bugreport.cgi?mbox=yes&bug=$1$2 [L,R,NE] + elsif ($path =~ m{^/?\s*mbox:\#?(\d+)((?:[;&].+)?)$}i) { + redirect($cgi,$base_uri."/cgi-bin/bugreport.cgi?mbox=yes;bug=$1$2"); + } + # RewriteRule ^/src:([^/]+)$ /cgi-bin/pkgreport.cgi?src=$1 [L,R,NE] + elsif ($path =~ m{^/?src:([^/]+)$}i) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?src=$1"); + } + # RewriteRule ^/severity:([^/]+)$ /cgi-bin/pkgreport.cgi?severity=$1 [L,R,NE] + elsif ($path =~ m{^/?severity:([^/]+)$}i) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?severity=$1"); + } + # RewriteRule ^/tag:([^/]+)$ /cgi-bin/pkgreport.cgi?tag=$1 [L,R,NE] + elsif ($path =~ m{^/?tag:([^/]+)$}i) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?tag=$1"); + } + # RewriteRule ^/([^/]+)$ /cgi-bin/pkgreport.cgi?pkg=$1 [L,R,NE] + elsif ($path =~ m{^/?([^/]+)$}i) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?pkg=$1"); + } + elsif ($path =~ m{^/?cgi(?:-bin)?/((?:(?:bug|pkg)report|version)\.cgi)}) { + my @exec_options = "$options{cgi_bin}/$1"; + if ($options{git_mode}) { + unshift @exec_options, + 'perl','-I',$options{base_dir},'-T'; + } + open(my $fh,'-|',@exec_options) or + die "Unable to execute $options{cgi_bin}/$1"; + my $status; + my $cache = ''; + while (<$fh>) { + if (/Status: (\d+\s+.+?)\n?$/) { + $status = $1; + print "HTTP/1.1 $status\n"; + print STDERR "'$status'\n"; + last; + } + $cache .= $_; + if (/^$/) { + print "HTTP/1.1 200 OK\n"; + last; + } + } + print $cache; + print <$fh>; + close($fh) or die "Unable to close"; + } + elsif ($path =~ m{^/?css/bugs.css}) { + my $fh = IO::File->new($options{css},'r') or + die "Unable to open $options{css} for reading: $!"; + print "HTTP/1.1 200 OK\n"; + print "Content-type: text/css\n"; + print "\n"; + print <$fh>; + } + elsif ($path =~ m{^/?$}) { + redirect($cgi,$base_uri."/cgi-bin/pkgreport.cgi?package=put%20package%20here"); + } + else { + print "HTTP/1.1 404 Not Found\n"; + print "Content-Type: text/html\n"; + print "\n"; + print "