App-LintPrereqs
view release on metacpan or search on metacpan
lib/App/LintPrereqs.pm view on Meta::CPAN
package App::LintPrereqs;
use 5.010001;
use strict;
use warnings;
use Log::ger;
use Config::IOD;
use Exporter 'import';
use Fcntl qw(:DEFAULT);
use File::Find;
use File::Which;
use Filename::Type::Backup qw(check_backup_filename);
use IPC::System::Options 'system', -log=>1;
use Module::CoreList::More;
use Proc::ChildError qw(explain_child_error);
use Scalar::Util 'looks_like_number';
use Sort::Sub qw(prereq_ala_perlancar);
use Version::Util qw(version_gt version_ne);
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
our $DATE = '2024-12-21'; # DATE
our $DIST = 'App-LintPrereqs'; # DIST
our $VERSION = '0.544'; # VERSION
our %SPEC;
our @EXPORT_OK = qw(lint_prereqs);
# create a merged list of prereqs from any phase
sub _create_prereqs_for_Any_phase {
my $prereqs = shift;
$prereqs->{Any} = {};
for my $phase (grep {$_ ne 'Any'} keys %$prereqs) {
for my $mod (keys %{ $prereqs->{$phase} }) {
my $v = $prereqs->{$phase}{$mod};
if (exists $prereqs->{Any}{$mod}) {
$prereqs->{Any}{$mod} = $v
if version_gt($v, $prereqs->{Any}{$mod});
} else {
$prereqs->{Any}{$mod} = $v;
}
}
}
}
sub _scan_prereqs {
my %args = @_;
my $scanner = do {
if ($args{scanner} eq 'lite') {
require Perl::PrereqScanner::Lite;
my $scanner = Perl::PrereqScanner::Lite->new;
$scanner->add_extra_scanner('Moose');
$scanner->add_extra_scanner('Version');
$scanner;
} elsif ($args{scanner} eq 'nqlite') {
require Perl::PrereqScanner::NotQuiteLite;
my $scanner = Perl::PrereqScanner::NotQuiteLite->new(
parsers => [qw/:installed -UniversalVersion/],
suggests => 1,
);
$scanner;
} else {
require Perl::PrereqScanner;
Perl::PrereqScanner->new;
}
};
require File::Find;
my %files; # key=phase, val=[file, ...]
{
$files{Runtime} = [];
my @dirs = (grep {-d} (
"lib", "bin", "script", "scripts",
#"sample", "samples", "example", "examples" # decidedly not included
#"share", # decidedly not included
lib/App/LintPrereqs.pm view on Meta::CPAN
$pkg =~ s/\.pm$//;
$dist_pkgs{$pkg}++;
},
}, "t/lib") if -d "t/lib";
log_trace("Dist packages (in tests): %s", \%test_dist_pkgs);
my %mods_from_scanned = _scan_prereqs(
scanner => $args{lite} ? 'lite' : $args{scanner},
extra_runtime_dirs => $args{extra_runtime_dirs},
extra_test_dirs => $args{extra_test_dirs},
);
log_trace("mods_from_scanned: %s", \%mods_from_scanned);
my $perlv_ini = $mods_from_ini{Any}{perl};
my $perlv_scanned = $mods_from_scanned{Any}{perl};
if ($perlv_scanned) {
if (!defined $perlv_ini) {
push @errs, {
module => 'perl',
req_v => $perlv_scanned,
is_core => 1,
error => "perl version specified in source code but not in dist.ini",
remedy => 'Add to dist.ini',
remedy_cmds => [
["pdrutil", "add-prereq", "perl", $perlv_scanned],
],
};
} elsif (version_ne($perlv_ini, $perlv_scanned)) {
return [500, "Perl version from dist.ini ($perlv_ini) ".
"and scan_prereqs ($perlv_scanned) mismatch"];
}
} else {
return [500, "Perl version not specified by source code but specified in dist.ini ".
"($perlv_ini)"] if $perlv_ini;
}
my $versions;
{
last unless $args{-cmdline_r};
$versions = $args{-cmdline_r}{config}{versions};
}
my $perlv; # min perl v to use in x.yyyzzz (numified)format
if ($args{perl_version}) {
log_trace("Will assume perl %s (via perl_version argument)",
$args{perl_version});
$perlv = $args{perl_version};
} elsif ($mods_from_ini{Any}{perl}) {
log_trace("Will assume perl %s (via dist.ini)",
$mods_from_ini{Any}{perl});
$perlv = $mods_from_ini{Any}{perl};
} elsif ($mods_from_scanned{Any}{perl}) {
log_trace("Will assume perl %s (via scan_prereqs)",
$mods_from_scanned{Any}{perl});
$perlv = $mods_from_scanned{Any}{perl};
} else {
log_trace("Will assume perl %s (from running interpreter's \$^V)",
$^V);
if ($^V =~ /^v(\d+)\.(\d+)\.(\d+)/) {
$perlv = sprintf("%d\.%03d%03d", $1, $2, $3)+0;
} elsif (looks_like_number($^V)) {
$perlv = $^V;
} else {
return [500, "Can't parse \$^V ($^V)"];
}
}
# check modules that are specified in dist.ini but extraneous (unused) or
# have mismatched version or phase
{
for my $mod (keys %{$mods_from_ini{Any}}) {
my $v = $mods_from_ini{Any}{$mod};
next if $mod eq 'perl';
log_trace("Checking mod from dist.ini: %s (%s)", $mod, $v);
my $is_core = Module::CoreList::More->is_still_core($mod, $v, $perlv);
if (!$args{core_prereqs} && $is_core) {
push @errs, {
module => $mod,
req_v => $v,
is_core => 1,
error => "Core in perl ($perlv to latest) but ".
"mentioned in dist.ini",
remedy => "Remove from dist.ini",
remedy_cmds => [
["pdrutil", "remove-prereq", $mod],
],
};
}
my $scanv = $mods_from_scanned{Any}{$mod};
if (defined($scanv) && $scanv != 0 && version_ne($v, $scanv)) {
push @errs, {
module => $mod,
req_v => $v,
is_core => $is_core,
error => "Version mismatch between dist.ini ($v) ".
"and from scanned_prereqs ($scanv)",
remedy => "Fix either the code or version in dist.ini",
};
}
if (defined($mods_from_scanned{Test}{$mod}) &&
!defined($mods_from_scanned{Runtime}{$mod}) &&
!defined($mods_from_ini{Test}{$mod}) &&
defined($mods_from_ini{Runtime}{$mod})) {
push @errs, {
module => $mod,
req_v => $v,
is_core => $is_core,
error => "Only used in test phase but listed under runtime prereq in dist.ini",
remedy => "Move prereq from runtime to test prereq in dist.ini",
remedy_cmds => [
["pdrutil", "remove-prereq", $mod],
["pdrutil", "add-prereq", $mod, $v, "--phase", "test"],
],
};
}
if (defined($mods_from_scanned{Runtime}{$mod}) &&
defined($mods_from_ini{Test}{$mod}) &&
!defined($mods_from_ini{Runtime}{$mod})) {
push @errs, {
module => $mod,
req_v => $v,
( run in 1.707 second using v1.01-cache-2.11-cpan-39bf76dae61 )