From: Don Armstrong Date: Thu, 16 Oct 2014 00:42:57 +0000 (-0700) Subject: Add Debbugs::BugWalker to abstract out bug-walking code in X-Git-Url: https://git.donarmstrong.com/?p=debbugs.git;a=commitdiff_plain;h=refs%2Fheads%2Fbugwalker_abstraction Add Debbugs::BugWalker to abstract out bug-walking code in debbugs-loadsql (and maybe eventually bugscan and elsewhere) --- diff --git a/Debbugs/BugWalker.pm b/Debbugs/BugWalker.pm new file mode 100644 index 0000000..1b1a714 --- /dev/null +++ b/Debbugs/BugWalker.pm @@ -0,0 +1,164 @@ +# This module is part of debbugs, and is released +# under the terms of the GPL version 2, or any later +# version at your option. +# See the file README and COPYING for more information. +# +# Copyright 2014 by Don Armstrong . + +package Debbugs::BugWalker; + +=head1 NAME + +Debbugs::BugWalker -- Walk through all known bugs + +=head1 SYNOPSIS + + use Debbugs::BugWalker; + my $w = Debbugs::BugWalker->new(); + +=head1 DESCRIPTION + +This module contains routines to walk through all known bugs (and +return specific files or bug numbers). + +=head1 BUGS + +=head1 FUNCTIONS + +=cut + +use warnings; +use strict; +use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT); +use base qw(Exporter); + +BEGIN{ + $VERSION = 1.00; + $DEBUG = 0 unless defined $DEBUG; + + @EXPORT = (); + %EXPORT_TAGS = (); + @EXPORT_OK = (); + $EXPORT_TAGS{all} = [@EXPORT_OK]; +} + +use Debbugs::Config qw(:config); +use Debbugs::Common qw(make_list); +use Moo; +use IO::File; +use IO::Dir; + +=head1 Functions + +=over + +=item Cnew()> + +Create a new bugwalker object to walk through available bugs. + +Takes the following options + +=over + +=item progress + +L to update progress on a terminal dynamically +(optional) + +=cut + +has progress => + (is => 'ro', + isa => sub { + if (not defined $_[0] or + $_[0]->can('update') + ) { + die "Progress must support ->update"; + } + } + ); + +=item dirs + +Directories to use to search for bugs; defaults to +C<$config{spool_dir}> + +=cut + +has dirs => + (is => 'ro', + ); + +=item what + +What files/directories to return. Defaults to bug, but must be one of +summary, bug, log, or status. + +=cut + +has what => + (is => 'ro', + isa => sub { + die "Must be one of summary, bug, log, status, version, or debinfo" + unless $_[0] =~ /^(?:summary|bug|log|status|version|debinfo)$/; + }); + + +=back + +=back + +=cut + +sub get_next { + my ($self) = @_; + + if (not defined $self->{_dirs}) { + $self->{_dirs} = [make_list($self->dirs())]; + $self->{_done_dirs} = 0; + $self->{_done_files} = 0; + $self->{_avg_subfiles} = 0; + } + if (not defined $self->{_files}) { + $self->{_files} = []; + } + while (not @{$self->{_files}}) { + my $next_dir = shift @{$self->{_dirs}}; + my $nd = IO::Dir->new($next_dir) or + die "Unable to open $next_dir for reading: $!"; + my $f; + while (defined ($f = $nd->read)) { + my $fn = File::Spec->catfile($next_dir,$f); + if (-d $fn) { + push @{$self->{_dirs}},$fn; + $self->{_total_dirs}++; + } elsif (-r _) { + if ($self->{what} eq 'bug') { + next unless $fn =~ /(\d+)\.status$/; + push @{$self->{_files}}, $1; + } else { + next unless $fn =~ /\.$self->{what}$/; + push @{$self->{_files}}, $fn; + } + } + } + if (defined $self->progress) { + $self->progress->target($self->{_avg_subfiles}*$self->{_dirs}+ + $self->{_done_files}+@{$self->{_files}}); + $self->{_avg_subfiles} = + ($self->{_avg_subfiles}*$self->{_done_dirs}+@{$self->{_files}})/ + ($self->{_done_dirs}+1); + } + $self->{_done_dirs}++; + } + if (@{$self->{_files}}) { + $self->progress->update($self->{done_files}++); + return shift @{$self->{_files}}; + } + return undef; +} + + +1; + +__END__ diff --git a/bin/debbugs-loadsql b/bin/debbugs-loadsql index b36a499..c96b59a 100755 --- a/bin/debbugs-loadsql +++ b/bin/debbugs-loadsql @@ -104,6 +104,7 @@ use Debbugs::Status qw(read_bug split_status_fields); use Debbugs::Log; use Debbugs::DB; use Debbugs::DB::Load qw(load_bug handle_load_bug_queue); +use Debbugs::BugWalker; use DateTime; use File::stat; @@ -220,32 +221,12 @@ sub add_bugs { my %tags; my %severities; my %queue; - my $tot_dirs = @{$argv}? @{$argv} : 0; - my $done_dirs = 0; - my $avg_subfiles = 0; - my $completed_files = 0; - while (my $dir = shift @dirs) { - printf "Doing dir %s ...\n", $dir if $verbose; - - opendir(DIR, "$dir/.") or die "opendir $dir: $!"; - my @subdirs = readdir(DIR); - closedir(DIR); - - my @list = map { m/^(\d+)\.summary$/?($1):() } @subdirs; - $tot_dirs -= @dirs; - push @dirs, map { m/^(\d+)$/ && -d "$dir/$1"?("$dir/$1"):() } @subdirs; - $tot_dirs += @dirs; - if ($avg_subfiles == 0) { - $avg_subfiles = @list; - } - - $p->target($avg_subfiles*($tot_dirs-$done_dirs)+$completed_files+@list) if $p; - $avg_subfiles = ($avg_subfiles * $done_dirs + @list) / ($done_dirs+1); - $done_dirs += 1; - - for my $bug (@list) { - $completed_files++; - $p->update($completed_files) if $p; + my $w = Debbugs::BugWalker->new(dir => [@dirs], + defined $p ? (progress => $p):(), + what => 'bug', + ); + my $bug; + while (defined($bug = $w->get_next())) { print "Up to $cnt bugs...\n" if (++$cnt % 100 == 0 && $verbose); my $stat = stat(getbugcomponent($bug,'summary',$initialdir)); if (not defined $stat) { @@ -270,7 +251,6 @@ sub add_bugs { print STDERR Dumper($data) if $DEBUG; die "failure while trying to load bug $bug\n$@"; } - } } $p->remove() if $p; handle_load_bug_queue(db => $s,