/usr/local/CPAN/HTML-WebMake/HTML/WebMake/DataSources/DirOfFiles.pm
#
package HTML::WebMake::DataSources::DirOfFiles;
require Exporter;
use File::Find;
use Carp;
use strict;
use HTML::WebMake::DataSourceBase;
use HTML::WebMake::MetaTable;
use vars qw{
@ISA @EXPORT
$TmpGlobalSelf
};
@ISA = qw(HTML::WebMake::DataSourceBase);
@EXPORT = qw();
###########################################################################
sub new {
my $class = shift;
$class = ref($class) || $class;
my $self = $class->SUPER::new (@_);
bless ($self, $class);
$self;
}
# -------------------------------------------------------------------------
sub add {
my ($self) = @_;
local ($_);
my $main = $self->{main};
my $src = $self->{src};
if ($src eq '') { $src = '.'; }
my $use_find = 0;
if ($self->{name} =~ s/^(RE:|)\.\.\.\//$1/) {
$use_find = 1;
}
my $patt = $main->{util}->glob_to_re ($self->{name});
my $pattskip = $main->{util}->glob_to_re ($self->{skip});
my $pattmetas = $main->{util}->glob_to_re ($self->{metatable});
my @matched;
my @matchedmetas;
$self->{metas} = 0;
if (defined $pattmetas) {
$self->{metas} = 1;
dbg ("searching for files that match \"$patt\" or \"$pattmetas\"");
} else {
dbg ("searching for files that match \"$patt\"");
}
$src =~ s,/+$,,;
my $realsrc;
if ($main->{base_dir} ne '') {
$realsrc = File::Spec->catdir ($main->{base_dir}, $src);
} else {
$realsrc = $src;
}
# this regexp is used to convert "/home/jm/jmason.org/raw/index.txt"
# to just "index.txt", when "raw" is the searched dir and "/home/jm/jmason.org"
# is the $main->{base_dir}.
$self->{real_to_underdir_re} = qr/\Q$realsrc\E/;
if ($use_find) {
$self->{found} = [ ];
$self->{foundmetas} = [ ];
if ($patt =~ m,/,) {
$self->{find_using_full_path} = 1;
$patt =~ s/^\^/\//; # replace start-of-string marker with /
if (defined $pattskip) { $pattskip =~ s/^\^/\//; }
if (defined $pattmetas) { $pattmetas =~ s/^\^/\//; }
} else {
$self->{find_using_full_path} = 0;
}
$self->{find_file_pattern} = $patt;
$self->{find_file_pattern_skip} = $pattskip;
$self->{find_file_pattern_metas} = $pattmetas;
$TmpGlobalSelf = $self;
find (\&find_wanted, $realsrc);
undef $TmpGlobalSelf;
@matched = @{$self->{found}};
delete $self->{found};
if ($self->{metas}) {
@matchedmetas = @{$self->{foundmetas}};
delete $self->{foundmetas};
}
} else {
if (!opendir (DIR, $realsrc)) {
warn "can't open ".$self->as_string()." src dir \"$realsrc\": $!\n";
return;
}
# grep for files that (a) match the pattern and (b) are files, not dirs
my @files = readdir(DIR);
@matched = grep {
/^${patt}$/ &&
(!defined $pattskip || !/^${pattskip}$/) &&
-f (File::Spec->catfile ($realsrc, $_));
} @files;
if (defined $pattmetas) {
@matchedmetas = grep {
/^${pattmetas}$/ &&
(!defined $pattskip || !/^${pattskip}$/) &&
-f (File::Spec->catfile ($realsrc, $_));
} @files;
}
closedir DIR;
}
# add all the data content items
foreach my $name (@matched) {
my $fname = File::Spec->catfile ($realsrc, $name);
my $mtime = $main->cached_get_modtime ($fname);
if (!defined $mtime || $mtime == 0) {
warn "cannot stat file $fname\n";
next;
}
$main->add_source_files ($fname);
my $fixed = $self->{parent}->fixname ($name);
$self->{parent}->add_file_to_list ($fixed);
$self->{parent}->add_location ($fixed, "file:".$fname, $mtime);
}
# and parse all the metadata files
foreach my $name (@matchedmetas) {
my $fname = File::Spec->catfile ($realsrc, $name);
my $mtime = $main->cached_get_modtime ($fname);
if (!defined $mtime || $mtime == 0) {
warn "cannot stat file $fname\n";
next;
}
$main->add_source_files ($fname);
open (IN, "<$fname");
my $text = join ('', <IN>);
close IN;
# if the metatable was loaded from a subdir, all the content
# items in that dir will be called e.g. "foo/bar/baz", but the
# metatable will contain references to "baz". Fix this...
$self->{metatable_name_prefix} = '';
if ($name =~ /^(.+[\/\\])[^\/\\]+/) {
$self->{metatable_name_prefix} = $1;
}
my $tbl = new HTML::WebMake::MetaTable ($self->{main});
$tbl->set_name_sed_callback ($self, \&fix_names_for_metatable);
$tbl->parse_metatable ($self->{attrs}, $text);
}
}
sub fix_names_for_metatable {
my ($self, $name) = @_;
$name = $self->{metatable_name_prefix} . $name;
$name = $self->{parent}->fixname ($name);
return $name;
}
sub find_wanted {
-f $_ or return; # ensure not a dir etc.
my $self = $TmpGlobalSelf;
my $matchstr;
if ($self->{find_using_full_path}) {
$matchstr = $File::Find::name;
} else {
$matchstr = $_;
}
my $skip = $self->{find_file_pattern_skip};
return if (defined $skip && $matchstr =~ /${skip}/);
($matchstr =~ /$self->{find_file_pattern}/) and $self->found_datafile();
if ($self->{metas}) {
($matchstr =~ /$self->{find_file_pattern_metas}/) and $self->found_metafile();
}
}
sub found_datafile {
my $self = shift;
my $name = $File::Find::name;
$name =~ s/^$self->{real_to_underdir_re}\/+//g;
push (@{$self->{found}}, $name);
}
sub found_metafile {
my $self = shift;
my $name = $File::Find::name;
$name =~ s/^$self->{real_to_underdir_re}\/+//g;
push (@{$self->{foundmetas}}, $name);
}
# -------------------------------------------------------------------------
sub get_location_url {
my ($self, $fname) = @_;
$fname =~ s/^file://;
return $fname;
}
# -------------------------------------------------------------------------
sub get_location_contents {
my ($self, $fname) = @_;
$fname =~ s/^file://;
if (!open (IN, "<$fname")) {
carp "cannot open file \"$fname\"\n"; return "";
}
my $text = join ('', <IN>); close IN;
return $text;
}
# -------------------------------------------------------------------------
sub get_location_mod_time {
my ($self, $fname) = @_;
$fname =~ /^file:/;
$self->{main}->cached_get_modtime ($');
}
# -------------------------------------------------------------------------
sub dbg { HTML::WebMake::Main::dbg (@_); }
# -------------------------------------------------------------------------
1;