BATsh
view release on metacpan or search on metacpan
t/lib/INA_CPAN_Check.pm view on Meta::CPAN
# Every .pm and .t under $dir, recursively, as paths relative to nothing
# (they keep the $dir prefix they were found with).
sub _find_pm_t {
my ($dir) = @_;
local *_INA_DIR;
opendir(_INA_DIR, $dir) or return ();
my @entries = grep { !/^\./ } readdir(_INA_DIR);
closedir _INA_DIR;
my @found;
for my $e (sort @entries) {
my $path = "$dir/$e";
if (-d $path) {
push @found, _find_pm_t($path);
}
elsif ($e =~ /\.(?:pm|t)$/) {
push @found, $path;
}
}
return @found;
}
sub _manifest_files {
my ($root) = @_;
my @lines = _slurp_lines("$root/MANIFEST");
my @files;
for my $line (@lines) {
$line =~ s/\r?\n$//;
$line =~ s/\s*#.*$//;
$line =~ s/^\s+|\s+$//g;
push @files, $line if length $line;
}
return @files;
}
# The files that carry ina@CPAN hand-written code: lib/*.pm, every *.t,
# and eg/*.pl. Driven by MANIFEST so that generated or vendored files
# outside it are never scanned.
sub _manifest_pm_and_t {
my ($root) = @_;
my @all = _manifest_files($root);
my @found = grep {
((/\.pm$/ && m{^lib/}) || /\.t$/ || m{^eg/.*\.pl$}) && -f "$root/$_"
} @all;
return @found if @found;
# Fallback for a dist with no usable MANIFEST.
my @fb;
for my $dir ('lib', 't') {
push @fb, _find_pm_t("$root/$dir") if -d "$root/$dir";
}
for my $p (@fb) {
$p =~ s{^\Q$root\E/}{};
}
return @fb;
}
# MANIFEST entries that are text and therefore subject to the encoding
# checks. Anything with a known binary extension is excluded.
sub _text_files {
my ($root) = @_;
return grep { !/\.(?:gz|tgz|zip|tar|bz2|png|jpe?g|gif|ico|pdf)$/i }
_manifest_files($root);
}
# Find $pattern in $path, ignoring POD, __END__, comments, string literals
# and regex literals, so that a match is real code and not prose or data.
# Returns a list of { line => N, text => "..." }.
sub _scan_code {
my ($path, $pattern) = @_;
my $text = _slurp($path);
return () unless $text ne '';
$text =~ s/\n__END__\b.*\z//s;
$text =~ s/^=[a-zA-Z].*?^=cut[ \t]*$//msg;
my @hits;
my $lineno = 0;
for my $line (split /\n/, $text) {
$lineno++;
next if $line =~ /^\s*#/;
my $clean = $line;
$clean =~ s/'(?:[^'\\]|\\.)*'/''/g;
$clean =~ s/"(?:[^"\\]|\\.)*"/""/g;
$clean =~ s{(?:s|m|qr|split\s*/)[^/]*/[^/]*/[gimsex]*}{}g;
$clean =~ s{/[^/]+/[gimsex]*}{}g;
$clean =~ s/#.*$//;
if ($clean =~ $pattern) {
push @hits, { line => $lineno, text => $line };
}
}
return @hits;
}
# Code with POD and __END__ removed, for whole-file pattern matching.
sub _code_only {
my ($path) = @_;
my $text = _slurp($path);
$text =~ s/\n__END__\b.*\z//s;
$text =~ s/^=[a-zA-Z].*?^=cut[ \t]*$//msg;
return $text;
}
######################################################################
# Distribution and metadata utilities
######################################################################
sub _dist_name {
my ($root) = @_;
my $base = $root;
$base =~ s{.*[/\\]}{};
$base =~ s{-[\d.]+$}{};
return $base;
}
# The primary module is the first MANIFEST entry (ina convention, as used
# by pmake.bat). Deriving it from MANIFEST is robust regardless of the
# directory name or a trailing "/.." that rel2abs leaves in $root.
sub _primary_pm {
my ($root) = @_;
if (-f "$root/MANIFEST") {
my @manifest = _manifest_files($root);
if (@manifest && $manifest[0] =~ /\.pm$/ && -f "$root/$manifest[0]") {
return "$root/$manifest[0]";
( run in 2.432 seconds using v1.01-cache-2.11-cpan-5c0b1e786e0 )