#!/usr/bin/perl # Filename: bugz # Author: David Ljung Madison # See License: http://MarginalHacks.com/License/ # Description: Fetch and output bugs from a bugzilla site use strict; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; my ($BASENAME,$PROGNAME) = ($0 =~ m|(.*)/(.+)|) ? ($1?$1:'/',$2) : ('.',$0); # Bugzilla info here (or as commandline args) my $DEFAULT_OPTS = { user => '', # Password can be optionally saved here pass => '', # Cookies file (if not in .mozilla) cookies => '', # The bugzilla URL (ends in .cgi) bugzilla => 'https//some.site.somewhere/bugzilla/buglist.cgi', # The default output format (with %keys%) fmt => 'Bug %bug_id%: %priority% %bug_status%/%resolution% %short_short_desc%\n', }; my $WGET = 'wget'; ################################################## # Usage ################################################## sub fatal { foreach my $msg (@_) { print STDERR "[$PROGNAME] ERROR: $msg\n"; } exit(-1); } sub usage { foreach my $msg (@_) { print STDERR "ERROR: $msg\n"; } print STDERR <{user} = shift @ARGV; next; } if ($arg =~ /^-pass$/) { $opt->{pass} = shift @ARGV; next; } if ($arg =~ /^-cookies$/) { $opt->{cookies} = shift @ARGV; next; } if ($arg =~ /^-bugzilla$/) { $opt->{bugzilla} = shift @ARGV; next; } if ($arg =~ /^-status$/) { push(@{$opt->{status}},shift @ARGV); next; } if ($arg =~ /^-component$/) { push(@{$opt->{component}},shift @ARGV); next; } if ($arg =~ /^-product$/) { push(@{$opt->{product}},shift @ARGV); next; } if ($arg =~ /^-fmt$/) { $opt->{fmt} = shift @ARGV; next; } if ($arg =~ /^-d$/) { $MAIN::DEBUG=1; next; } if ($arg =~ /^-/) { usage("Unknown option: $arg"); } usage("Unknown option: $arg\n"); } $opt; } sub debug { return unless $MAIN::DEBUG; foreach my $msg (@_) { print STDERR "[$PROGNAME] $msg\n"; } } ################################################## # Main code ################################################## sub cookies() { my ($opt) = @_; my @cookies; push(@cookies,$opt->{cookies}) if $opt->{cookies}; # Netscape push(@cookies,".netscape/cookies.txt") if -r ".netscape/cookies.txt"; # Mozilla cookies? push(@cookies,glob("$ENV{HOME}/.mozilla/*/*/cookies.txt")); map { "--load-cookies=$_" } @cookies; } sub status { my ($opt,@s) = @_; @s = @{$opt->{status}} unless @s || !$opt->{status}; @s = ('ALL') unless @s; map { uc } @s; my @status; foreach my $s ( @s ) { if ($s eq 'ALL') { push(@status,status($opt,qw(NEW ASSIGNED REOPENED RESOLVED VERIFIED CLOSED))); } elsif ($s eq 'OPEN') { push(@status,status($opt,qw(NEW ASSIGNED REOPENED RESOLVED VERIFIED))); } else { push(@status,$s); } } join('',map { "&bug_status=$_" } @status); } sub addKey { my ($opt,@key) = @_; my $ret; foreach my $key ( @key ) { next unless $opt->{$key}; foreach my $v ( @{$opt->{$key}} ) { $ret .= "&$key=$v"; } } $ret; } sub csvSplit() { my @csv; chomp; while ($_) { fatal("Couldn't parse csv: [$_]\n") unless s/^([^",][^,]*)(,|$)// || s/^"(.*?)"(,|$)// || s/^()(,|$)//; push(@csv,$1); } @csv; } sub command { my ($opt) = @_; my $url = "$opt->{bugzilla}?ctype=csv"; $url .= status($opt); $url .= addKey($opt,'component','product'); my @cmd = ($WGET,"--quiet", "--user=$opt->{user}", "--password=\Q$opt->{pass}\E", "--no-check-certificate", "-O","-", "\Q$url\E"); push(@cmd,cookies); @cmd; } sub getBugz { my ($opt,@cmd) = @_; open(BUGZ,"@cmd |") || usage("Couldn't open pipe [$opt->{bugzilla}]"); my @head; my (@bugz); while() { if ($.==1) { @head = csvSplit; } else { my @csv = csvSplit; fatal("Number of elements in csv changed??") if $#head != $#csv; my %bug; foreach my $h ( @head ) { $bug{$h} = shift @csv; } push(@bugz, \%bug); } } close BUGZ; @bugz; } sub outputBugz { my ($opt,@bugz) = @_; foreach my $b ( @bugz ) { my $fmt = $opt->{fmt}; $fmt =~ s/\\n/\n/g; $fmt =~ s/%([^%]+)%/$b->{$1}/g; print $fmt; } } sub main { my $opt = parse_args(); my @cmd = command($opt); my @bugz = getBugz($opt,@cmd); outputBugz($opt,@bugz); } main();