package Dondley::WestfieldVote::FileCollector ; use strict; use warnings; use Cwd; use Carp; use File::Basename; use Log::Log4perl::Shortcuts qw(:all); { my $iterator; sub _file_iterator { my @files = @_; my $f = sub { shift @files; }; return $f; } sub get_next_file { my $s = shift; if (!$s->{_selected_file}) { my @files = @_ ? @_ : $s->get_files; $iterator = _file_iterator(@files) if !$iterator; } my $next_file = $iterator->(); $s->{_selected_file} = $next_file; $iterator = '' if !$next_file; return $next_file; } } sub AUTOLOAD { our $AUTOLOAD; my $s = shift; $AUTOLOAD =~ /.*::get(_next)*(_\w+)_files*$/ or croak "No such method: $AUTOLOAD"; my ($next, $type) = ($1, $2); my $attr = "${type}_files"; my @files = @{$s->{$attr}}; return if !@files || !$next; return $s->get_next_file(@files); } sub new { my $class = shift; my $s = bless { _files => {}, _target_repo => '', _selected_file => '', _common_dir => ''}, $class; $s->add_resources(@_); return $s; } sub get_count { my $s = shift; return (scalar keys %{$s->{_files}}) } sub get_obj_prop { my $s = shift; my $obj = shift; my $prop = shift; if (!$prop || !$obj) { $s->croak ("Missing arguments to get_obj_prop method" . ' at ' . (caller(0))[1] . ', line ' . (caller(0))[2] ); } my $file = $s->{_selected_file}; my $o = $obj . '_obj'; my $object = $s->{_files}{$file}{$o}; my $attr = "_$prop"; if (! exists $object->{$attr} ) { $s->croak ("Non-existent $obj object attribute requested: '$prop'" . ' at ' . (caller(0))[1] . ', line ' . (caller(0))[2] ); } my $value = $object->{$attr}; if (ref $value eq 'ARRAY') { return @$value; } else { return $value; } } sub set_obj_prop { my $s = shift; my $obj = shift; my $prop = shift; my $val = shift; if (!$prop || !$obj) { $s->croak ("Missing arguments to get_obj_prop method" . ' at ' . (caller(0))[1] . ', line ' . (caller(0))[2] ); } my $file = $s->{_selected_file}; my $o = $obj . '_obj'; my $object = $s->{_files}{$file}{$o}; my $attr = "_$prop"; if (! exists $object->{$attr} ) { $s->croak ("Non-existent $obj object attribute requested: '$prop'" . ' at ' . (caller(0))[1] . ', line ' . (caller(0))[2] ); } $object->{$attr} = $val; } sub add_obj { my ($s, $type, $obj) = @_; my $file = $s->{_selected_file}; my $ot = "${type}_obj"; $s->{_files}{$file}{$ot} = $obj; } sub selected_file { my $s = shift; return $s->{_selected_file}; } sub has_obj { my $s = shift; my $type = shift; if (!$type) { $s->croak ("Missing argument to has method" . ' at ' . (caller(0))[1] . ', line ' . (caller(0))[2] ); } my $file = shift || $s->{_selected_file}; my $to = "${type}_obj"; return defined $s->{_files}{$file}{$to}; } sub get_files { my $s = shift; my @files = sort keys %{$s->{_files}}; return @files; } sub add_resources { my ($s, @resources) = @_; foreach my $resource (@resources) { _exists($resource); $s->_add_file($resource) if -f $resource; $s->_get_file_manifest($resource) if -d $resource; } $s->_generate_short_names; } sub list_files_long { my $s = shift; my @files = $s->get_files; print $_ . "\n" for @files; } sub list_files { my $s = shift; my @files = map { $s->{_files}{$_}{short_path} } keys %{$s->{_files}}; print "\nFiles found in '".$s->{_common_dir}."':\n\n"; print $_ . "\n" for @files; } sub print_short_name { my $s = shift; print $s->short_name . "\n"; } sub short_name { my $s = shift; my $file = $s->{_selected_file}; $s->{_files}{$file}{short_path}; } sub _generate_short_names { my $s = shift; my @files = $s->get_files; my $file = pop @files; my @comps = split /\//, $file; my ($new_string, $longest_string) = ''; foreach my $cfile (@files) { my @ccomps = split /\//, $cfile; my $lc = 0; foreach my $comp (@ccomps) { if (defined $comps[$lc] && $ccomps[$lc] eq $comps[$lc]) { $new_string .= $ccomps[$lc++] . '/'; next; } $longest_string = $new_string; @comps = split /\//, $new_string; $new_string = ''; last; } } $s->{_common_dir} = $longest_string || (fileparse($file))[1]; if (@files) { foreach my $file ( @files, $file ) { $s->{_files}{$file}{short_path} = $file =~ s/$longest_string//r; } } else { $s->{_files}{$file}{short_path} = $file; } } sub get_filename { my $s = shift; my $file = $s->{_selected_file} || shift; return $s->{_files}{$file}{filename}; } sub _add_file { my ($s, $file) = @_; $file = $s->_make_absolute($file); $s->{_files}{$file}{full_path} = $file; my $filename = (fileparse($file))[0]; $s->{_files}{$file}{filename} = $filename; } sub _make_absolute { my ($s, $file) = @_; return $file =~ /^\// ? $file : cwd() . "/$file"; } sub _get_file_manifest { my ($s, $dir) = @_; opendir (my $dh, $dir) or die "Can't opendir $dir: $!"; my @dirs_and_files = grep { /^[^\.]/ } readdir($dh); my @files = grep { -f "$dir/$_" } @dirs_and_files; $s->_add_file("$dir/$_") for @files; my @dirs = grep { -d "$dir/$_" } @dirs_and_files; foreach my $tdir (@dirs) { opendir (my $tdh, "$dir/$tdir") || die "Can't opendir $tdir: $!"; $s->_get_file_manifest("$dir/$tdir"); } } sub _exists { croak "'$_[0]' does not exist. Aborting." if ! -e $_[0]; } sub _croak { my $msg = shift; croak $msg . ' at ' . (caller(1))[1] . ', line ' . (caller(1))[2]; } sub DESTROY { } 1; # Magic true value