diff --git a/author/cpm/Dockerfile b/author/cpm/Dockerfile index 6c0736f6e..37621f8f7 100644 --- a/author/cpm/Dockerfile +++ b/author/cpm/Dockerfile @@ -9,13 +9,7 @@ RUN curl --compressed -sSL https://raw.githubusercontent.com/tokuhirom/Perl-Buil RUN apk del perl patch ENV PATH=/opt/perl-5.8/bin:$PATH -RUN curl --compressed -sSL https://cpanmin.us/ | perl - --notest Distribution::Metadata@0.06 App::FatPacker::Simple@0.09 Carton ExtUtils::PL2Bat +RUN curl --compressed -sSL https://cpanmin.us/ | perl - --notest Carton ExtUtils::PL2Bat RUN mkdir -p /tmp/cpm WORKDIR /tmp/cpm - -COPY cpanfile . -COPY build.pl . -COPY cpanfile.snapshot . - -RUN carton install --deployment diff --git a/author/cpm/Makefile b/author/cpm/Makefile index f12759f2d..ebaafe478 100644 --- a/author/cpm/Makefile +++ b/author/cpm/Makefile @@ -14,20 +14,30 @@ image: .image.exists ## build docker image of packing environment docker build -t $(IMAGE_NAME) . touch .image.exists -.container.exists: .image.exists - -docker rm $(IMAGE_NAME)-tmp - docker run --name $(IMAGE_NAME)-tmp $(IMAGE_NAME) perl build.pl - touch .container.exists - -cpm: .container.exists ## generate fat-packed cpm - docker cp $(IMAGE_NAME)-tmp:/tmp/cpm/cpm cpm +cpm: .deps.exists build.pl ## generate fat-packed cpm + cat build.pl | docker run --rm -i --volumes-from $(IMAGE_NAME)-deps $(IMAGE_NAME) perl - + docker cp $(IMAGE_NAME)-deps:/tmp/cpm/cpm cpm + +.PHONY: deps +deps: .deps.exists ## install dependencies +.DELETE_ON_ERROR: .deps.exists +.deps.exists: .image.exists cpanfile.snapshot + touch .deps.exists + -docker rm $(IMAGE_NAME)-deps + docker create -v /tmp/cpm --name $(IMAGE_NAME)-deps $(IMAGE_NAME) /bin/true + docker cp cpanfile $(IMAGE_NAME)-deps:/tmp/cpm/cpanfile + docker cp cpanfile.snapshot $(IMAGE_NAME)-deps:/tmp/cpm/cpanfile.snapshot + docker run --rm --volumes-from $(IMAGE_NAME)-deps $(IMAGE_NAME) carton install --deployment + docker cp $(IMAGE_NAME)-deps:/tmp/cpm/local . .PHONY: update update: .image.exists ## download dependencies and update cpanfile.snapshot -docker rm $(IMAGE_NAME)-update - docker run --name $(IMAGE_NAME)-update $(IMAGE_NAME) \ - sh -c "rm -f cpanfile.snapshot && rm -rf local && carton install" + docker create -v /tmp/cpm --name $(IMAGE_NAME)-update $(IMAGE_NAME) /bin/true + docker cp cpanfile $(IMAGE_NAME)-update:/tmp/cpm/cpanfile + docker run --rm --volumes-from $(IMAGE_NAME)-update $(IMAGE_NAME) carton install docker cp $(IMAGE_NAME)-update:/tmp/cpm/cpanfile.snapshot cpanfile.snapshot + -docker rm $(IMAGE_NAME)-update .PHONY: install install: all ## installs into the bin directory of this repository diff --git a/author/cpm/build.pl b/author/cpm/build.pl index 2ec067f37..dd7859db3 100644 --- a/author/cpm/build.pl +++ b/author/cpm/build.pl @@ -3,6 +3,7 @@ use strict; use warnings; use FindBin; +use lib "$FindBin::Bin/local/lib/perl5"; use App::FatPacker::Simple; use Carton::Snapshot; use ExtUtils::PL2Bat qw/pl2bat/; @@ -20,6 +21,14 @@ sub fatpack { 'ExtUtils::CBuilder', 'ExtUtils::MakeMaker::CPANfile', 'Module::Build::Tiny', 'ExtUtils::ParseXS', 'Devel::GlobalDestruction::XS', + # fat-packing + 'App::FatPacker', 'App::FatPacker::Simple', + 'Clone', 'Distribution::Metadata', + 'ExtUtils::CBuilder', 'ExtUtils::ParseXS', + 'IO::String', 'JSON', 'Module::Build::Tiny', 'PPI', + 'Params::Util', 'Cwd', 'List::Util', + 'Perl::Strip', 'Scalar::Util', 'Storable', + 'Task::Weaken', 'Perl::OSType', 'XSLoader', 'common::sense', # test modules 'Test2', 'App::Prove','TAP::Harness', 'Perl::OSType', # core modules of perl 5 diff --git a/author/cpm/cpanfile b/author/cpm/cpanfile index 8a5f26886..eb4ebb709 100644 --- a/author/cpm/cpanfile +++ b/author/cpm/cpanfile @@ -2,6 +2,9 @@ requires 'perl', '5.006'; requires "Devel::GlobalDestruction::XS"; requires "Module::Build::Tiny"; requires 'CPAN::Meta::Requirements', '==2.140'; # 2.141 doesn't support perl 5.8. +requires 'Distribution::Metadata', '==0.06'; +requires 'App::FatPacker::Simple', '==0.09'; +requires 'Module::Build::Tiny', '==0.047'; # 0.048 doesn't work on perl 5.8. requires "App::cpm"; requires "Class::C3"; diff --git a/author/cpm/cpanfile.snapshot b/author/cpm/cpanfile.snapshot index 77b14e780..615d77f47 100644 --- a/author/cpm/cpanfile.snapshot +++ b/author/cpm/cpanfile.snapshot @@ -8,10 +8,38 @@ DISTRIBUTIONS Carp 0.01 ExtUtils::MakeMaker 0 perl 5.006 - App-cpm-0.997015 - pathname: S/SK/SKAJI/App-cpm-0.997015.tar.gz + App-FatPacker-0.010008 + pathname: M/MS/MSTROUT/App-FatPacker-0.010008.tar.gz provides: - App::cpm 0.997015 + App::FatPacker 0.010008 + App::FatPacker::Trace undef + requirements: + B 1.01 + Cwd 0 + ExtUtils::MakeMaker 0 + File::Copy 0 + File::Find 0 + File::Path 0 + File::Spec::Functions 0 + File::Spec::Unix 0 + Getopt::Long 0 + perl 5.008000 + App-FatPacker-Simple-0.09 + pathname: S/SK/SKAJI/App-FatPacker-Simple-0.09.tar.gz + provides: + App::FatPacker::Simple 0.09 + App::FatPacker::Simple::Tutorial undef + requirements: + App::FatPacker 0 + Distribution::Metadata 0.05 + Module::Build::Tiny 0.034 + Perl::Strip 0 + Pod::Usage 1.33 + perl 5.008001 + App-cpm-0.997017 + pathname: S/SK/SKAJI/App-cpm-0.997017.tar.gz + provides: + App::cpm 0.997017 App::cpm::CLI undef App::cpm::CircularDependency undef App::cpm::DistNotation undef @@ -223,6 +251,12 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 + Clone-0.46 + pathname: G/GA/GARU/Clone-0.46.tar.gz + provides: + Clone 0.46 + requirements: + ExtUtils::MakeMaker 0 Command-Runner-0.200 pathname: S/SK/SKAJI/Command-Runner-0.200.tar.gz provides: @@ -252,6 +286,19 @@ DISTRIBUTIONS provides: Devel::GlobalDestruction::XS 0.03 requirements: + Distribution-Metadata-0.06 + pathname: S/SK/SKAJI/Distribution-Metadata-0.06.tar.gz + provides: + Distribution::Metadata 0.06 + Distribution::Metadata::Factory undef + requirements: + CPAN::DistnameInfo 0 + CPAN::Meta 0 + ExtUtils::Packlist 0 + JSON 0 + Module::Build::Tiny 0.034 + Module::Metadata 0 + perl 5.008001 ExtUtils-CBuilder-0.280236 pathname: A/AM/AMBS/ExtUtils-CBuilder-0.280236.tar.gz provides: @@ -592,6 +639,14 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Test::More 0.31 Time::HiRes 0 + JSON-4.10 + pathname: I/IS/ISHIGAKI/JSON-4.10.tar.gz + provides: + JSON 4.10 + JSON::Backend::PP 4.10 + requirements: + ExtUtils::MakeMaker 0 + Test::More 0 JSON-PP-4.16 pathname: I/IS/ISHIGAKI/JSON-PP-4.16.tar.gz provides: @@ -707,11 +762,11 @@ DISTRIBUTIONS CPAN::Meta::Prereqs 2.12091 ExtUtils::MakeMaker 0 parent 0 - Module-CoreList-5.20240320 - pathname: B/BI/BINGOS/Module-CoreList-5.20240320.tar.gz + Module-CoreList-5.20240609 + pathname: B/BI/BINGOS/Module-CoreList-5.20240609.tar.gz provides: - Module::CoreList 5.20240320 - Module::CoreList::Utils 5.20240320 + Module::CoreList 5.20240609 + Module::CoreList::Utils 5.20240609 requirements: ExtUtils::MakeMaker 0 List::Util 0 @@ -766,6 +821,118 @@ DISTRIBUTIONS Scalar::Util 0 YAML::PP 0.027 perl 5.008001 + PPI-1.278 + pathname: O/OA/OALDERS/PPI-1.278.tar.gz + provides: + PPI 1.278 + PPI::Cache 1.278 + PPI::Document 1.278 + PPI::Document::File 1.278 + PPI::Document::Fragment 1.278 + PPI::Document::Normalized 1.278 + PPI::Dumper 1.278 + PPI::Element 1.278 + PPI::Exception 1.278 + PPI::Exception::ParserRejection 1.278 + PPI::Find 1.278 + PPI::Lexer 1.278 + PPI::Node 1.278 + PPI::Normal 1.278 + PPI::Normal::Standard 1.278 + PPI::Singletons 1.278 + PPI::Statement 1.278 + PPI::Statement::Break 1.278 + PPI::Statement::Compound 1.278 + PPI::Statement::Data 1.278 + PPI::Statement::End 1.278 + PPI::Statement::Expression 1.278 + PPI::Statement::Given 1.278 + PPI::Statement::Include 1.278 + PPI::Statement::Include::Perl6 1.278 + PPI::Statement::Null 1.278 + PPI::Statement::Package 1.278 + PPI::Statement::Scheduled 1.278 + PPI::Statement::Sub 1.278 + PPI::Statement::Unknown 1.278 + PPI::Statement::UnmatchedBrace 1.278 + PPI::Statement::Variable 1.278 + PPI::Statement::When 1.278 + PPI::Structure 1.278 + PPI::Structure::Block 1.278 + PPI::Structure::Condition 1.278 + PPI::Structure::Constructor 1.278 + PPI::Structure::For 1.278 + PPI::Structure::Given 1.278 + PPI::Structure::List 1.278 + PPI::Structure::Subscript 1.278 + PPI::Structure::Unknown 1.278 + PPI::Structure::When 1.278 + PPI::Token 1.278 + PPI::Token::ArrayIndex 1.278 + PPI::Token::Attribute 1.278 + PPI::Token::BOM 1.278 + PPI::Token::Cast 1.278 + PPI::Token::Comment 1.278 + PPI::Token::DashedWord 1.278 + PPI::Token::Data 1.278 + PPI::Token::End 1.278 + PPI::Token::HereDoc 1.278 + PPI::Token::Label 1.278 + PPI::Token::Magic 1.278 + PPI::Token::Number 1.278 + PPI::Token::Number::Binary 1.278 + PPI::Token::Number::Exp 1.278 + PPI::Token::Number::Float 1.278 + PPI::Token::Number::Hex 1.278 + PPI::Token::Number::Octal 1.278 + PPI::Token::Number::Version 1.278 + PPI::Token::Operator 1.278 + PPI::Token::Pod 1.278 + PPI::Token::Prototype 1.278 + PPI::Token::Quote 1.278 + PPI::Token::Quote::Double 1.278 + PPI::Token::Quote::Interpolate 1.278 + PPI::Token::Quote::Literal 1.278 + PPI::Token::Quote::Single 1.278 + PPI::Token::QuoteLike 1.278 + PPI::Token::QuoteLike::Backtick 1.278 + PPI::Token::QuoteLike::Command 1.278 + PPI::Token::QuoteLike::Readline 1.278 + PPI::Token::QuoteLike::Regexp 1.278 + PPI::Token::QuoteLike::Words 1.278 + PPI::Token::Regexp 1.278 + PPI::Token::Regexp::Match 1.278 + PPI::Token::Regexp::Substitute 1.278 + PPI::Token::Regexp::Transliterate 1.278 + PPI::Token::Separator 1.278 + PPI::Token::Structure 1.278 + PPI::Token::Symbol 1.278 + PPI::Token::Unknown 1.278 + PPI::Token::Whitespace 1.278 + PPI::Token::Word 1.278 + PPI::Tokenizer 1.278 + PPI::Transform 1.278 + PPI::Transform::UpdateCopyright 1.278 + PPI::Util 1.278 + PPI::XSAccessor 1.278 + requirements: + Carp 0 + Clone 0.30 + Digest::MD5 2.35 + Exporter 0 + ExtUtils::MakeMaker 0 + File::Path 0 + File::Spec 0.84 + List::Util 1.33 + Params::Util 1.00 + Scalar::Util 0 + Storable 2.17 + Task::Weaken 0 + constant 0 + if 0 + overload 0 + perl 5.006 + strict 0 Parallel-Pipes-0.200 pathname: S/SK/SKAJI/Parallel-Pipes-0.200.tar.gz provides: @@ -782,6 +949,22 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Locale::Maketext::Simple 0 Test::More 0 + Params-Util-1.102 + pathname: R/RE/REHSACK/Params-Util-1.102.tar.gz + provides: + Params::Util 1.102 + Params::Util::PP 1.102 + requirements: + Carp 0 + ExtUtils::MakeMaker 0 + File::Basename 0 + File::Copy 0 + File::Path 0 + File::Spec 0 + IPC::Cmd 0 + Scalar::Util 1.18 + XSLoader 0.22 + parent 0 Parse-PMFile-0.47 pathname: I/IS/ISHIGAKI/Parse-PMFile-0.47.tar.gz provides: @@ -824,6 +1007,15 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 + Perl-Strip-1.2 + pathname: M/ML/MLEHMANN/Perl-Strip-1.2.tar.gz + provides: + Perl::Strip 1.2 + requirements: + Digest::MD5 2 + ExtUtils::MakeMaker 0 + PPI 1.213 + common::sense 3.3 Proc-ForkSafe-0.001 pathname: S/SK/SKAJI/Proc-ForkSafe-0.001.tar.gz provides: @@ -831,6 +1023,16 @@ DISTRIBUTIONS requirements: Module::Build::Tiny 0.034 perl 5.008001 + Scalar-List-Utils-1.63 + pathname: P/PE/PEVANS/Scalar-List-Utils-1.63.tar.gz + provides: + List::Util 1.63 + List::Util::XS 1.63 + Scalar::Util 1.63 + Sub::Util 1.63 + requirements: + ExtUtils::MakeMaker 0 + perl 5.006 Search-Dict-1.07 pathname: D/DA/DAGOLDEN/Search-Dict-1.07.tar.gz provides: @@ -840,6 +1042,13 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Test::More 0.47 Tie::Handle 0 + Storable-3.25 + pathname: N/NW/NWCLARK/Storable-3.25.tar.gz + provides: + Storable 3.25 + requirements: + ExtUtils::MakeMaker 6.31 + XSLoader 0 String-ShellQuote-1.04 pathname: R/RO/ROSCH/String-ShellQuote-1.04.tar.gz provides: @@ -852,6 +1061,17 @@ DISTRIBUTIONS Sub::Exporter::Progressive 0.001013 requirements: ExtUtils::MakeMaker 0 + Task-Weaken-1.06 + pathname: E/ET/ETHER/Task-Weaken-1.06.tar.gz + provides: + Task::Weaken 1.06 + requirements: + Config 0 + ExtUtils::MakeMaker 0 + File::Spec 0 + Scalar::Util 1.14 + perl 5.006 + strict 0 Test-Harness-3.48 pathname: L/LE/LEONT/Test-Harness-3.48.tar.gz provides: @@ -1073,6 +1293,13 @@ DISTRIBUTIONS Win32::ShellQuote 0.003001 requirements: perl 5.006 + XSLoader-0.24 + pathname: S/SA/SAPER/XSLoader-0.24.tar.gz + provides: + XSLoader 0.24 + requirements: + ExtUtils::MakeMaker 0 + Test::More 0.47 YAML-PP-v0.38.0 pathname: T/TI/TINITA/YAML-PP-v0.38.0.tar.gz provides: @@ -1129,6 +1356,12 @@ DISTRIBUTIONS perl 5.008000 strict 0 warnings 0 + common-sense-3.75 + pathname: M/ML/MLEHMANN/common-sense-3.75.tar.gz + provides: + common::sense 3.75 + requirements: + ExtUtils::MakeMaker 0 local-lib-2.000029 pathname: H/HA/HAARG/local-lib-2.000029.tar.gz provides: @@ -1143,13 +1376,13 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 perl 5.006 - version-0.9930 - pathname: L/LE/LEONT/version-0.9930.tar.gz + version-0.9932 + pathname: L/LE/LEONT/version-0.9932.tar.gz provides: - version 0.9930 - version::regex 0.9930 - version::vpp 0.9930 - version::vxs 0.9930 + version 0.9932 + version::regex 0.9932 + version::vpp 0.9932 + version::vxs 0.9932 requirements: ExtUtils::MakeMaker 0 perl 5.006002 diff --git a/bin/cpm b/bin/cpm index f37e92860..1fda16a84 100755 --- a/bin/cpm +++ b/bin/cpm @@ -9,11 +9,11 @@ $fatpacked{"Algorithm/C3.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'AL ALGORITHM_C3 $fatpacked{"App/cpm.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'APP_CPM'; - package App::cpm;use strict;use warnings;our$VERSION='0.997015';our ($GIT_DESCRIBE,$GIT_URL);1; + package App::cpm;use strict;use warnings;our$VERSION='0.997017';our ($GIT_DESCRIBE,$GIT_URL);1; APP_CPM $fatpacked{"App/cpm/CLI.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'APP_CPM_CLI'; - package App::cpm::CLI;use 5.008001;use strict;use warnings;use App::cpm::DistNotation;use App::cpm::Distribution;use App::cpm::Logger::File;use App::cpm::Logger;use App::cpm::Master;use App::cpm::Requirement;use App::cpm::Resolver::Cascade;use App::cpm::Resolver::MetaCPAN;use App::cpm::Resolver::MetaDB;use App::cpm::Util qw(WIN32 determine_home maybe_abs);use App::cpm::Worker;use App::cpm::version;use App::cpm;use CPAN::Meta;use Command::Runner;use Config;use Cwd ();use File::Copy ();use File::Path ();use File::Spec;use Getopt::Long qw(:config no_auto_abbrev no_ignore_case bundling);use List::Util ();use Module::CPANfile;use Module::cpmfile;use Parallel::Pipes::App;use Pod::Text ();use local::lib ();sub new {my ($class,%option)=@_;my$prebuilt=exists$ENV{PERL_CPM_PREBUILT}&&!$ENV{PERL_CPM_PREBUILT}? 0 : 1;bless {argv=>undef,home=>determine_home,cwd=>Cwd::cwd(),workers=>WIN32 ? 1 : 5,snapshot=>"cpanfile.snapshot",dependency_file=>undef,local_lib=>"local",cpanmetadb=>"https://cpanmetadb.plackperl.org/v1.0/",_default_mirror=>'https://cpan.metacpan.org/',retry=>1,configure_timeout=>60,build_timeout=>3600,test_timeout=>1800,with_requires=>1,with_recommends=>0,with_suggests=>0,with_configure=>0,with_build=>1,with_test=>1,with_runtime=>1,with_develop=>0,feature=>[],notest=>1,prebuilt=>$] >= 5.012 && $prebuilt,pureperl_only=>0,static_install=>1,default_resolvers=>1,%option },$class}sub parse_options {my$self=shift;local@ARGV=@_;my ($mirror,@resolver,@feature);my$with_option=sub {my$n=shift;("with-$n",\$self->{"with_$n"},"without-$n",sub {$self->{"with_$n"}=0})};my@type=qw(requires recommends suggests);my@phase=qw(configure build test runtime develop);GetOptions "L|local-lib-contained=s"=>\($self->{local_lib}),"color!"=>\($self->{color}),"g|global"=>\($self->{global}),"mirror=s"=>\$mirror,"v|verbose"=>\($self->{verbose}),"w|workers=i"=>\($self->{workers}),"target-perl=s"=>\my$target_perl,"test!"=>sub {$self->{notest}=$_[1]? 0 : 1},"cpanfile=s"=>sub {$self->{dependency_file}={type=>"cpanfile",path=>$_[1]}},"cpmfile=s"=>sub {$self->{dependency_file}={type=>"cpmfile",path=>$_[1]}},"metafile=s"=>sub {$self->{dependency_file}={type=>"metafile",path=>$_[1]}},"snapshot=s"=>\($self->{snapshot}),"sudo"=>\($self->{sudo}),"r|resolver=s@"=>\@resolver,"default-resolvers!"=>\($self->{default_resolvers}),"mirror-only"=>\($self->{mirror_only}),"dev"=>\($self->{dev}),"man-pages"=>\($self->{man_pages}),"home=s"=>\($self->{home}),"retry!"=>\($self->{retry}),"exclude-vendor!"=>\($self->{exclude_vendor}),"configure-timeout=i"=>\($self->{configure_timeout}),"build-timeout=i"=>\($self->{build_timeout}),"test-timeout=i"=>\($self->{test_timeout}),"show-progress!"=>\($self->{show_progress}),"prebuilt!"=>\($self->{prebuilt}),"reinstall"=>\($self->{reinstall}),"pp|pureperl|pureperl-only"=>\($self->{pureperl_only}),"static-install!"=>\($self->{static_install}),"with-all"=>sub {map {$self->{"with_$_"}=1}@type,@phase},(map$with_option->($_),@type),(map$with_option->($_),@phase),"feature=s@"=>\@feature,"show-build-log-on-failure"=>\($self->{show_build_log_on_failure}),or return 0;$self->{local_lib}=maybe_abs($self->{local_lib},$self->{cwd})unless$self->{global};$self->{home}=maybe_abs($self->{home},$self->{cwd});$self->{resolver}=\@resolver;$self->{feature}=\@feature if@feature;$self->{mirror}=$self->normalize_mirror($mirror)if$mirror;$self->{color}=1 if!defined$self->{color}&& -t STDOUT;$self->{show_progress}=1 if!WIN32 &&!defined$self->{show_progress}&& -t STDOUT;if ($target_perl){die "--target-perl option conflicts with --global option\n" if$self->{global};die "--target-perl option can be used only if perl version >= 5.18.0\n" if $] < 5.018;$target_perl="v$target_perl" if$target_perl =~ /^5\.[1-9]\d*$/;$target_perl=sprintf '%0.6f',App::cpm::version->parse($target_perl)->numify;$target_perl='5.008' if$target_perl eq '5.008000';$self->{target_perl}=$target_perl}if (WIN32 and $self->{workers}!=1){die "The number of workers must be 1 under WIN32 environment.\n"}if ($self->{sudo}){!system "sudo",$^X,"-e1" or exit 1}if ($self->{pureperl_only}or $self->{sudo}or!$self->{notest}or $self->{man_pages}or $] < 5.012){$self->{prebuilt}=0}$App::cpm::Logger::COLOR=1 if$self->{color};$App::cpm::Logger::VERBOSE=1 if$self->{verbose};$App::cpm::Logger::SHOW_PROGRESS=1 if$self->{show_progress};if (@ARGV){if ($ARGV[0]eq "-"){my$argv=$self->read_argv_from_stdin;return -1 if @$argv==0;$self->{argv}=$argv}else {$self->{argv}=\@ARGV}}elsif (!$self->{dependency_file}){$self->{dependency_file}=$self->locate_dependency_file}return 1}sub read_argv_from_stdin {my$self=shift;my@argv;while (my$line=){next if$line !~ /\S/;next if$line =~ /^\s*#/;$line =~ s/^\s*//;$line =~ s/\s*$//;push@argv,split /\s+/,$line}return \@argv}sub _core_inc {my$self=shift;[(!$self->{exclude_vendor}? grep {$_}@Config{qw(vendorarch vendorlibexp)}: ()),@Config{qw(archlibexp privlibexp)},]}sub _search_inc {my$self=shift;return \@INC if$self->{global};my$base=$self->{local_lib};my@local_lib=(local::lib->resolve_path(local::lib->install_base_arch_path($base)),local::lib->resolve_path(local::lib->install_base_perl_path($base)),);if ($self->{target_perl}){return [@local_lib]}else {return [@local_lib,@{$self->_core_inc}]}}sub normalize_mirror {my ($self,$mirror)=@_;$mirror =~ s{/*$}{/};return$mirror if$mirror =~ m{^https?://};$mirror =~ s{^file://}{};die "$mirror: No such directory.\n" unless -d $mirror;"file://" .maybe_abs($mirror,$self->{cwd})}sub run {my ($self,@argv)=@_;my$cmd=shift@argv or die "Need subcommand, try `cpm --help`\n";$cmd="help" if$cmd =~ /^(-h|--help)$/;$cmd="version" if$cmd =~ /^(-V|--version)$/;if (my$sub=$self->can("cmd_$cmd")){return$self->$sub(@argv)if$cmd eq "exec";my$ok=$self->parse_options(@argv);return 1 if!$ok;return 0 if$ok==-1;return$self->$sub}else {my$message=$cmd =~ /^-/ ? "Missing subcommand" : "Unknown subcommand '$cmd'";die "$message, try `cpm --help`\n"}}sub cmd_help {open my$fh,">",\my$out;Pod::Text->new->parse_from_file($0,$fh);$out =~ s/^[ ]{6}/ /mg;print$out;return 0}sub cmd_version {print "cpm $App::cpm::VERSION ($0)\n";if ($App::cpm::GIT_DESCRIBE){print "This is a self-contained version, $App::cpm::GIT_DESCRIBE ($App::cpm::GIT_URL)\n"}printf "perl version v%vd ($^X)\n\n",$^V;print " \%Config:\n";for my$key (qw(archname installsitelib installsitebin installman1dir installman3dir sitearchexp sitelibexp vendorarch vendorlibexp archlibexp privlibexp)){print " $key=$Config{$key}\n" if$Config{$key}}print " \%ENV:\n";for my$key (grep /^PERL/,sort keys%ENV){print " $key=$ENV{$key}\n"}print " \@INC:\n";for my$inc (@INC){print " $inc\n" unless ref($inc)eq 'CODE'}return 0}sub cmd_install {my$self=shift;die "Need arguments or cpm.yml/cpanfile/Build.PL/Makefile.PL\n" if!$self->{argv}&&!$self->{dependency_file};local%ENV=%ENV;File::Path::mkpath($self->{home})unless -d $self->{home};my$logger=App::cpm::Logger::File->new("$self->{home}/build.log.@{[time]}");$logger->symlink_to("$self->{home}/build.log");$logger->log("Running cpm $App::cpm::VERSION ($0) on perl $Config{version} built for $Config{archname} ($^X)");$logger->log("This is a self-contained version, $App::cpm::GIT_DESCRIBE ($App::cpm::GIT_URL)")if$App::cpm::GIT_DESCRIBE;$logger->log("Command line arguments are: @ARGV");my$master=App::cpm::Master->new(logger=>$logger,core_inc=>$self->_core_inc,search_inc=>$self->_search_inc,global=>$self->{global},show_progress=>$self->{show_progress},(exists$self->{target_perl}? (target_perl=>$self->{target_perl}): ()),);my ($packages,$dists,$resolver)=$self->initial_task($master);return 0 unless$packages;my$worker=App::cpm::Worker->new(verbose=>$self->{verbose},home=>$self->{home},logger=>$logger,notest=>$self->{notest},sudo=>$self->{sudo},resolver=>$self->generate_resolver($resolver),man_pages=>$self->{man_pages},retry=>$self->{retry},prebuilt=>$self->{prebuilt},pureperl_only=>$self->{pureperl_only},static_install=>$self->{static_install},configure_timeout=>$self->{configure_timeout},build_timeout=>$self->{build_timeout},test_timeout=>$self->{test_timeout},($self->{global}? (): (local_lib=>$self->{local_lib})),);{last if $] >= 5.018;my$requirement=App::cpm::Requirement->new('ExtUtils::MakeMaker'=>'6.64','ExtUtils::ParseXS'=>'3.16');for my$name ('ExtUtils::MakeMaker','ExtUtils::ParseXS'){if (my ($i)=grep {$packages->[$_]{package}eq $name}0..$#{$packages}){$requirement->add($name,$packages->[$i]{version_range})or die sprintf "We have to install newer $name first: $@\n";splice @$packages,$i,1}}my ($is_satisfied,@need_resolve)=$master->is_satisfied($requirement->as_array);last if$is_satisfied;$master->add_task(type=>"resolve",%$_)for@need_resolve;$self->install($master,$worker,1);if (my$fail=$master->fail){local$App::cpm::Logger::VERBOSE=0;for my$type (qw(install resolve)){App::cpm::Logger->log(result=>"FAIL",type=>$type,message=>$_)for @{$fail->{$type}}}print STDERR "\r" if$self->{show_progress};warn sprintf "%d distribution%s installed.\n",$master->installed_distributions,$master->installed_distributions > 1 ? "s" : "";if ($self->{show_build_log_on_failure}){File::Copy::copy($logger->file,\*STDERR)}else {warn "See $self->{home}/build.log for details.\n";warn "You may want to execute cpm with --show-build-log-on-failure,\n";warn "so that the build.log is automatically dumped on failure.\n"}return 1}}$master->add_task(type=>"resolve",%$_)for @$packages;$master->add_distribution($_)for @$dists;$self->install($master,$worker,$self->{workers});my$fail=$master->fail;if ($fail){local$App::cpm::Logger::VERBOSE=0;for my$type (qw(install resolve)){App::cpm::Logger->log(result=>"FAIL",type=>$type,message=>$_)for @{$fail->{$type}}}}print STDERR "\r" if$self->{show_progress};warn sprintf "%d distribution%s installed.\n",$master->installed_distributions,$master->installed_distributions > 1 ? "s" : "";$self->cleanup;if ($fail){if ($self->{show_build_log_on_failure}){File::Copy::copy($logger->file,\*STDERR)}else {warn "See $self->{home}/build.log for details.\n";warn "You may want to execute cpm with --show-build-log-on-failure,\n";warn "so that the build.log is automatically dumped on failure.\n"}return 1}else {return 0}}sub install {my ($self,$master,$worker,$num)=@_;my@task=$master->get_task;Parallel::Pipes::App->run(num=>$num,before_work=>sub {my$task=shift;$task->in_charge(1)},work=>sub {my$task=shift;return$worker->work($task)},after_work=>sub {my$result=shift;$master->register_result($result);@task=$master->get_task},tasks=>\@task,)}sub cleanup {my$self=shift;my$week=time - 7*24*60*60;my@entry=glob "$self->{home}/build.log.*";if (opendir my$dh,"$self->{home}/work"){push@entry,map File::Spec->catdir("$self->{home}/work",$_),grep!/^\.{1,2}$/,readdir$dh}for my$entry (@entry){my$mtime=(stat$entry)[9];if ($mtime < $week){if (-d $entry){File::Path::rmtree($entry)}else {unlink$entry}}}}sub initial_task {my ($self,$master)=@_;if (!$self->{argv}){my ($requirement,$reinstall,$resolver)=$self->load_dependency_file;my ($is_satisfied,@need_resolve)=$master->is_satisfied($requirement);if (!@$reinstall and $is_satisfied){warn "All requirements are satisfied.\n";return}elsif (!defined$is_satisfied){my ($req)=grep {$_->{package}eq "perl"}@$requirement;die sprintf "%s requires perl %s, but you have only %s\n",$self->{dependency_file}{path},$req->{version_range},$self->{target_perl}|| $]}my@package=(@need_resolve,@$reinstall);return (\@package,[],$resolver)}$self->{mirror}||= $self->{_default_mirror};my (@package,@dist);for (@{$self->{argv}}){my$arg=$_;my ($package,$dist);if (-d $arg || -f $arg || $arg =~ s{^file://}{}){$arg=maybe_abs($arg,$self->{cwd});$dist=App::cpm::Distribution->new(source=>"local",uri=>"file://$arg",provides=>[])}elsif ($arg =~ /(?:^git:|\.git(?:@.+)?$)/){my%ref=$arg =~ s/(?<=\.git)@(.+)$// ? (ref=>$1): ();$dist=App::cpm::Distribution->new(source=>"git",uri=>$arg,provides=>[],%ref)}elsif ($arg =~ m{^(https?|file)://}){my ($source,$distfile)=($1 eq "file" ? "local" : "http",undef);if (my$d=App::cpm::DistNotation->new_from_uri($arg)){($source,$distfile)=("cpan",$d->distfile)}$dist=App::cpm::Distribution->new(source=>$source,uri=>$arg,$distfile ? (distfile=>$distfile): (),provides=>[],)}elsif (my$d=App::cpm::DistNotation->new_from_dist($arg)){$dist=App::cpm::Distribution->new(source=>"cpan",uri=>$d->cpan_uri($self->{mirror}),distfile=>$d->distfile,provides=>[],)}else {my ($name,$version_range,$dev);$arg =~ s/^([A-Za-z0-9_:]+)@([v\d\._]+)$/$1~== $2/;if ($arg =~ /\~[v\d\._,\!<>= ]+$/){($name,$version_range)=split '~',$arg,2}else {$arg =~ s/[~@]dev$// and $dev++;$name=$arg}$package= +{package=>$name,version_range=>$version_range || 0,dev=>$dev,reinstall=>$self->{reinstall},}}push@package,$package if$package;push@dist,$dist if$dist}return (\@package,\@dist,undef)}sub locate_dependency_file {my$self=shift;if (-f "cpm.yml"){return {type=>"cpmfile",path=>"cpm.yml" }}if (-f "cpanfile"){return {type=>"cpanfile",path=>"cpanfile" }}if (-f 'META.json'){my$meta=CPAN::Meta->load_file('META.json');if (!$meta->dynamic_config){return {type=>'metafile',path=>'META.json' }}}if (-f 'Build.PL' || -f 'Makefile.PL'){my$build_file= -f 'Build.PL' ? 'Build.PL' : 'Makefile.PL';warn "Executing $build_file to generate MYMETA.json and to determine requirements...\n";local%ENV=(PERL5_CPAN_IS_RUNNING=>1,PERL5_CPANPLUS_IS_RUNNING=>1,PERL5_CPANM_IS_RUNNING=>1,PERL_MM_USE_DEFAULT=>1,%ENV,);if (!$self->{global}){local$SIG{__WARN__}=sub {};local::lib->setup_env_hash_for($self->{local_lib},0)}my$runner=Command::Runner->new(command=>[$^X,$build_file ],timeout=>60,redirect=>1,);my$res=$runner->run;if ($res->{timeout}){die "Error: timed out (>60s).\n$res->{stdout}"}if ($res->{result}!=0){die "Error: failed to execute $build_file.\n$res->{stdout}"}if (!-f 'MYMETA.json'){die "Error: No MYMETA.json after executing $build_file\n"}return {type=>'metafile',path=>'MYMETA.json' }}return}sub load_dependency_file {my$self=shift;my$cpmfile=do {my ($type,$path)=@{$self->{dependency_file}}{qw(type path)};warn "Loading requirements from $path...\n";if ($type eq "cpmfile"){Module::cpmfile->load($path)}elsif ($type eq "cpanfile"){Module::cpmfile->from_cpanfile(Module::CPANfile->load($path))}elsif ($type eq "metafile"){Module::cpmfile->from_cpanmeta(CPAN::Meta->load_file($path))}else {die}};if (!$self->{mirror}){my$mirrors=$cpmfile->{_mirrors}|| [];if (@$mirrors){$self->{mirror}=$self->normalize_mirror($mirrors->[0])}else {$self->{mirror}=$self->{_default_mirror}}}my@phase=grep$self->{"with_$_"},qw(configure build test runtime develop);my@type=grep$self->{"with_$_"},qw(requires recommends suggests);my$reqs=$cpmfile->effective_requirements($self->{feature},\@phase,\@type);my (@package,@reinstall);for my$package (sort keys %$reqs){my$options=$reqs->{$package};my$req={package=>$package,version_range=>$options->{version},dev=>$options->{dev},reinstall=>$options->{git}? 1 : 0,};if ($options->{git}){push@reinstall,$req}else {push@package,$req}}require App::cpm::Resolver::Custom;my$resolver=App::cpm::Resolver::Custom->new(requirements=>$reqs,mirror=>$self->{mirror},from=>$self->{dependency_file}{type},);return (\@package,\@reinstall,$resolver->effective ? $resolver : undef)}sub generate_resolver {my ($self,$initial)=@_;my$cascade=App::cpm::Resolver::Cascade->new;$cascade->add($initial)if$initial;if (@{$self->{resolver}}){for my$r (@{$self->{resolver}}){my ($klass,@argv)=split /,/,$r;my$resolver=$self->_generate_resolver($klass,@argv);$cascade->add($resolver)}}return$cascade if!$self->{default_resolvers};if ($self->{mirror_only}){require App::cpm::Resolver::02Packages;my$resolver=App::cpm::Resolver::02Packages->new(mirror=>$self->{mirror},cache=>"$self->{home}/sources",);$cascade->add($resolver);return$cascade}if (!$self->{argv}and -f $self->{snapshot}){if (!eval {require App::cpm::Resolver::Snapshot}){die "To load $self->{snapshot}, you need to install Carton::Snapshot.\n"}warn "Loading distributions from $self->{snapshot}...\n";my$resolver=App::cpm::Resolver::Snapshot->new(path=>$self->{snapshot},mirror=>$self->{mirror},);$cascade->add($resolver)}my$resolver=App::cpm::Resolver::MetaCPAN->new($self->{dev}? (dev=>1): (only_dev=>1));$cascade->add($resolver);$resolver=App::cpm::Resolver::MetaDB->new(uri=>$self->{cpanmetadb},mirror=>$self->{mirror},);$cascade->add($resolver);if (!$self->{dev}){$resolver=App::cpm::Resolver::MetaCPAN->new;$cascade->add($resolver)}$cascade}sub _generate_resolver {my ($self,$klass,@argv)=@_;if ($klass =~ /^metadb$/i){my ($uri,$mirror);if (@argv > 1){($uri,$mirror)=@argv}elsif (@argv==1){$mirror=$argv[0]}else {$mirror=$self->{mirror}}return App::cpm::Resolver::MetaDB->new($uri ? (uri=>$uri): (),mirror=>$self->normalize_mirror($mirror),)}elsif ($klass =~ /^metacpan$/i){return App::cpm::Resolver::MetaCPAN->new(dev=>$self->{dev})}elsif ($klass =~ /^02packages?$/i){require App::cpm::Resolver::02Packages;my ($path,$mirror);if (@argv > 1){($path,$mirror)=@argv}elsif (@argv==1){$mirror=$argv[0]}else {$mirror=$self->{mirror}}return App::cpm::Resolver::02Packages->new($path ? (path=>$path): (),cache=>"$self->{home}/sources",mirror=>$self->normalize_mirror($mirror),)}elsif ($klass =~ /^snapshot$/i){require App::cpm::Resolver::Snapshot;return App::cpm::Resolver::Snapshot->new(path=>$self->{snapshot},mirror=>@argv ? $self->normalize_mirror($argv[0]): $self->{mirror},)}my$full_klass=$klass =~ s/^\+// ? $klass : "App::cpm::Resolver::$klass";(my$file=$full_klass)=~ s{::}{/}g;require "$file.pm";return$full_klass->new(@argv)}1; + package App::cpm::CLI;use 5.008001;use strict;use warnings;use App::cpm::DistNotation;use App::cpm::Distribution;use App::cpm::Logger::File;use App::cpm::Logger;use App::cpm::Master;use App::cpm::Requirement;use App::cpm::Resolver::Cascade;use App::cpm::Resolver::MetaCPAN;use App::cpm::Resolver::MetaDB;use App::cpm::Util qw(WIN32 determine_home maybe_abs);use App::cpm::Worker;use App::cpm::version;use App::cpm;use CPAN::Meta;use Command::Runner;use Config;use Cwd ();use File::Copy ();use File::Path ();use File::Spec;use Getopt::Long qw(:config no_auto_abbrev no_ignore_case bundling);use List::Util ();use Module::CPANfile;use Module::cpmfile;use Parallel::Pipes::App;use Pod::Text ();use local::lib ();sub new {my ($class,%option)=@_;my$prebuilt=exists$ENV{PERL_CPM_PREBUILT}&&!$ENV{PERL_CPM_PREBUILT}? 0 : 1;bless {argv=>undef,home=>determine_home,cwd=>Cwd::cwd(),workers=>WIN32 ? 1 : 5,snapshot=>"cpanfile.snapshot",dependency_file=>undef,local_lib=>"local",cpanmetadb=>"https://cpanmetadb.plackperl.org/v1.0/",_default_mirror=>'https://cpan.metacpan.org/',retry=>1,configure_timeout=>60,build_timeout=>3600,test_timeout=>1800,with_requires=>1,with_recommends=>0,with_suggests=>0,with_configure=>0,with_build=>1,with_test=>1,with_runtime=>1,with_develop=>0,feature=>[],notest=>1,prebuilt=>$] >= 5.012 && $prebuilt,pureperl_only=>0,static_install=>1,default_resolvers=>1,%option },$class}sub parse_options {my$self=shift;local@ARGV=@_;my ($mirror,@resolver,@feature);my$with_option=sub {my$n=shift;("with-$n",\$self->{"with_$n"},"without-$n",sub {$self->{"with_$n"}=0})};my@type=qw(requires recommends suggests);my@phase=qw(configure build test runtime develop);GetOptions "L|local-lib-contained=s"=>\($self->{local_lib}),"color!"=>\($self->{color}),"g|global"=>\($self->{global}),"mirror=s"=>\$mirror,"v|verbose"=>\($self->{verbose}),"w|workers=i"=>\($self->{workers}),"target-perl=s"=>\my$target_perl,"test!"=>sub {$self->{notest}=$_[1]? 0 : 1},"cpanfile=s"=>sub {$self->{dependency_file}={type=>"cpanfile",path=>$_[1]}},"cpmfile=s"=>sub {$self->{dependency_file}={type=>"cpmfile",path=>$_[1]}},"metafile=s"=>sub {$self->{dependency_file}={type=>"metafile",path=>$_[1]}},"snapshot=s"=>\($self->{snapshot}),"sudo"=>\($self->{sudo}),"r|resolver=s@"=>\@resolver,"default-resolvers!"=>\($self->{default_resolvers}),"mirror-only"=>\($self->{mirror_only}),"dev"=>\($self->{dev}),"man-pages"=>\($self->{man_pages}),"home=s"=>\($self->{home}),"retry!"=>\($self->{retry}),"exclude-vendor!"=>\($self->{exclude_vendor}),"configure-timeout=i"=>\($self->{configure_timeout}),"build-timeout=i"=>\($self->{build_timeout}),"test-timeout=i"=>\($self->{test_timeout}),"show-progress!"=>\($self->{show_progress}),"prebuilt!"=>\($self->{prebuilt}),"reinstall"=>\($self->{reinstall}),"pp|pureperl|pureperl-only"=>\($self->{pureperl_only}),"static-install!"=>\($self->{static_install}),"with-all"=>sub {map {$self->{"with_$_"}=1}@type,@phase},(map$with_option->($_),@type),(map$with_option->($_),@phase),"feature=s@"=>\@feature,"show-build-log-on-failure"=>\($self->{show_build_log_on_failure}),or return 0;$self->{local_lib}=maybe_abs($self->{local_lib},$self->{cwd})unless$self->{global};$self->{home}=maybe_abs($self->{home},$self->{cwd});$self->{resolver}=\@resolver;$self->{feature}=\@feature if@feature;$self->{mirror}=$self->normalize_mirror($mirror)if$mirror;$self->{color}=1 if!defined$self->{color}&& -t STDOUT;$self->{show_progress}=1 if!WIN32 &&!defined$self->{show_progress}&& -t STDOUT;if ($target_perl){die "--target-perl option conflicts with --global option\n" if$self->{global};die "--target-perl option can be used only if perl version >= 5.18.0\n" if $] < 5.018;$target_perl="v$target_perl" if$target_perl =~ /^5\.[1-9]\d*$/;$target_perl=sprintf '%0.6f',App::cpm::version->parse($target_perl)->numify;$target_perl='5.008' if$target_perl eq '5.008000';$self->{target_perl}=$target_perl}if (WIN32 and $self->{workers}!=1){die "The number of workers must be 1 under WIN32 environment.\n"}if ($self->{sudo}){!system "sudo",$^X,"-e1" or exit 1}if ($self->{pureperl_only}or $self->{sudo}or!$self->{notest}or $self->{man_pages}or $] < 5.012){$self->{prebuilt}=0}$App::cpm::Logger::COLOR=1 if$self->{color};$App::cpm::Logger::VERBOSE=1 if$self->{verbose};$App::cpm::Logger::SHOW_PROGRESS=1 if$self->{show_progress};if (@ARGV){if ($ARGV[0]eq "-"){my$argv=$self->read_argv_from_stdin;return -1 if @$argv==0;$self->{argv}=$argv}else {$self->{argv}=\@ARGV}}elsif (!$self->{dependency_file}){$self->{dependency_file}=$self->locate_dependency_file}return 1}sub read_argv_from_stdin {my$self=shift;my@argv;while (my$line=){next if$line !~ /\S/;next if$line =~ /^\s*#/;$line =~ s/^\s*//;$line =~ s/\s*$//;push@argv,split /\s+/,$line}return \@argv}sub _core_inc {my$self=shift;[(!$self->{exclude_vendor}? grep {$_}@Config{qw(vendorarch vendorlibexp)}: ()),@Config{qw(archlibexp privlibexp)},]}sub _search_inc {my$self=shift;return \@INC if$self->{global};my$base=$self->{local_lib};my@local_lib=(local::lib->resolve_path(local::lib->install_base_arch_path($base)),local::lib->resolve_path(local::lib->install_base_perl_path($base)),);if ($self->{target_perl}){return [@local_lib]}else {return [@local_lib,@{$self->_core_inc}]}}sub normalize_mirror {my ($self,$mirror)=@_;$mirror =~ s{/*$}{/};return$mirror if$mirror =~ m{^https?://};$mirror =~ s{^file://}{};die "$mirror: No such directory.\n" unless -d $mirror;"file://" .maybe_abs($mirror,$self->{cwd})}sub run {my ($self,@argv)=@_;my$cmd=shift@argv or die "Need subcommand, try `cpm --help`\n";$cmd="help" if$cmd =~ /^(-h|--help)$/;$cmd="version" if$cmd =~ /^(-V|--version)$/;if (my$sub=$self->can("cmd_$cmd")){return$self->$sub(@argv)if$cmd eq "exec";my$ok=$self->parse_options(@argv);return 1 if!$ok;return 0 if$ok==-1;return$self->$sub}else {my$message=$cmd =~ /^-/ ? "Missing subcommand" : "Unknown subcommand '$cmd'";die "$message, try `cpm --help`\n"}}sub cmd_help {open my$fh,">",\my$out;Pod::Text->new->parse_from_file($0,$fh);$out =~ s/^[ ]{6}/ /mg;print$out;return 0}sub cmd_version {print "cpm $App::cpm::VERSION ($0)\n";if ($App::cpm::GIT_DESCRIBE){print "This is a self-contained version, $App::cpm::GIT_DESCRIBE ($App::cpm::GIT_URL)\n"}printf "perl version v%vd ($^X)\n\n",$^V;print " \%Config:\n";for my$key (qw(archname installsitelib installsitebin installman1dir installman3dir sitearchexp sitelibexp vendorarch vendorlibexp archlibexp privlibexp)){print " $key=$Config{$key}\n" if$Config{$key}}print " \%ENV:\n";for my$key (grep /^PERL/,sort keys%ENV){print " $key=$ENV{$key}\n"}print " \@INC:\n";for my$inc (@INC){print " $inc\n" unless ref($inc)eq 'CODE'}return 0}sub cmd_install {my$self=shift;die "Need arguments or cpm.yml/cpanfile/Build.PL/Makefile.PL\n" if!$self->{argv}&&!$self->{dependency_file};local%ENV=%ENV;File::Path::mkpath($self->{home})unless -d $self->{home};my$logger=App::cpm::Logger::File->new("$self->{home}/build.log.@{[time]}");$logger->symlink_to("$self->{home}/build.log");$logger->log("Running cpm $App::cpm::VERSION ($0) on perl $Config{version} built for $Config{archname} ($^X)");$logger->log("This is a self-contained version, $App::cpm::GIT_DESCRIBE ($App::cpm::GIT_URL)")if$App::cpm::GIT_DESCRIBE;$logger->log("Command line arguments are: @ARGV");my$master=App::cpm::Master->new(logger=>$logger,core_inc=>$self->_core_inc,search_inc=>$self->_search_inc,global=>$self->{global},show_progress=>$self->{show_progress},(exists$self->{target_perl}? (target_perl=>$self->{target_perl}): ()),);my ($packages,$dists,$resolver)=$self->initial_task($master);return 0 unless$packages;my$worker=App::cpm::Worker->new(verbose=>$self->{verbose},home=>$self->{home},logger=>$logger,notest=>$self->{notest},sudo=>$self->{sudo},resolver=>$self->generate_resolver($resolver),man_pages=>$self->{man_pages},retry=>$self->{retry},prebuilt=>$self->{prebuilt},pureperl_only=>$self->{pureperl_only},static_install=>$self->{static_install},configure_timeout=>$self->{configure_timeout},build_timeout=>$self->{build_timeout},test_timeout=>$self->{test_timeout},($self->{global}? (): (local_lib=>$self->{local_lib})),);{last if $] >= 5.018;my$requirement=App::cpm::Requirement->new('ExtUtils::MakeMaker'=>'6.64','ExtUtils::ParseXS'=>'3.16');for my$name ('ExtUtils::MakeMaker','ExtUtils::ParseXS'){if (my ($i)=grep {$packages->[$_]{package}eq $name}0..$#{$packages}){$requirement->add($name,$packages->[$i]{version_range})or die sprintf "We have to install newer $name first: $@\n";splice @$packages,$i,1}}my ($is_satisfied,@need_resolve)=$master->is_satisfied($requirement->as_array);last if$is_satisfied;$master->add_task(type=>"resolve",%$_)for@need_resolve;$self->install($master,$worker,1);if (my$fail=$master->fail){local$App::cpm::Logger::VERBOSE=0;for my$type (qw(install resolve)){App::cpm::Logger->log(result=>"FAIL",type=>$type,message=>$_)for @{$fail->{$type}}}print STDERR "\r" if$self->{show_progress};warn sprintf "%d distribution%s installed.\n",$master->installed_distributions,$master->installed_distributions > 1 ? "s" : "";if ($self->{show_build_log_on_failure}){File::Copy::copy($logger->file,\*STDERR)}else {warn "See $self->{home}/build.log for details.\n";warn "You may want to execute cpm with --show-build-log-on-failure,\n";warn "so that the build.log is automatically dumped on failure.\n"}return 1}}$master->add_task(type=>"resolve",%$_)for @$packages;$master->add_distribution($_)for @$dists;$self->install($master,$worker,$self->{workers});my$fail=$master->fail;if ($fail){local$App::cpm::Logger::VERBOSE=0;for my$type (qw(install resolve)){App::cpm::Logger->log(result=>"FAIL",type=>$type,message=>$_)for @{$fail->{$type}}}}print STDERR "\r" if$self->{show_progress};warn sprintf "%d distribution%s installed.\n",$master->installed_distributions,$master->installed_distributions > 1 ? "s" : "";$self->cleanup;if ($fail){if ($self->{show_build_log_on_failure}){File::Copy::copy($logger->file,\*STDERR)}else {warn "See $self->{home}/build.log for details.\n";warn "You may want to execute cpm with --show-build-log-on-failure,\n";warn "so that the build.log is automatically dumped on failure.\n"}return 1}else {return 0}}sub install {my ($self,$master,$worker,$num)=@_;if ($num > 1 && $^O eq "darwin" &&!exists$ENV{OBJC_DISABLE_INITIALIZE_FORK_SAFETY}&&!$self->{_darwin_fixed}){require Socket;Socket::inet_aton("call-inet_aton-before_fork");$self->{_darwin_fixed}=1}my@task=$master->get_task;Parallel::Pipes::App->run(num=>$num,before_work=>sub {my$task=shift;$task->in_charge(1)},work=>sub {my$task=shift;return$worker->work($task)},after_work=>sub {my$result=shift;$master->register_result($result);@task=$master->get_task},tasks=>\@task,)}sub cleanup {my$self=shift;my$week=time - 7*24*60*60;my@entry=glob "$self->{home}/build.log.*";if (opendir my$dh,"$self->{home}/work"){push@entry,map File::Spec->catdir("$self->{home}/work",$_),grep!/^\.{1,2}$/,readdir$dh}for my$entry (@entry){my$mtime=(stat$entry)[9];if ($mtime < $week){if (-d $entry){File::Path::rmtree($entry)}else {unlink$entry}}}}sub initial_task {my ($self,$master)=@_;if (!$self->{argv}){my ($requirement,$reinstall,$resolver)=$self->load_dependency_file;my ($is_satisfied,@need_resolve)=$master->is_satisfied($requirement);if (!@$reinstall and $is_satisfied){warn "All requirements are satisfied.\n";return}elsif (!defined$is_satisfied){my ($req)=grep {$_->{package}eq "perl"}@$requirement;die sprintf "%s requires perl %s, but you have only %s\n",$self->{dependency_file}{path},$req->{version_range},$self->{target_perl}|| $]}my@package=(@need_resolve,@$reinstall);return (\@package,[],$resolver)}$self->{mirror}||= $self->{_default_mirror};my (@package,@dist);for (@{$self->{argv}}){my$arg=$_;my ($package,$dist);if (-d $arg || -f $arg || $arg =~ s{^file://}{}){$arg=maybe_abs($arg,$self->{cwd});$dist=App::cpm::Distribution->new(source=>"local",uri=>"file://$arg",provides=>[])}elsif ($arg =~ /(?:^git:|\.git(?:@.+)?$)/){my%ref=$arg =~ s/(?<=\.git)@(.+)$// ? (ref=>$1): ();$dist=App::cpm::Distribution->new(source=>"git",uri=>$arg,provides=>[],%ref)}elsif ($arg =~ m{^(https?|file)://}){my ($source,$distfile)=($1 eq "file" ? "local" : "http",undef);if (my$d=App::cpm::DistNotation->new_from_uri($arg)){($source,$distfile)=("cpan",$d->distfile)}$dist=App::cpm::Distribution->new(source=>$source,uri=>$arg,$distfile ? (distfile=>$distfile): (),provides=>[],)}elsif (my$d=App::cpm::DistNotation->new_from_dist($arg)){$dist=App::cpm::Distribution->new(source=>"cpan",uri=>$d->cpan_uri($self->{mirror}),distfile=>$d->distfile,provides=>[],)}else {my ($name,$version_range,$dev);$arg =~ s/^([A-Za-z0-9_:]+)@([v\d\._]+)$/$1~== $2/;if ($arg =~ /\~[v\d\._,\!<>= ]+$/){($name,$version_range)=split '~',$arg,2}else {$arg =~ s/[~@]dev$// and $dev++;$name=$arg}$package= +{package=>$name,version_range=>$version_range || 0,dev=>$dev,reinstall=>$self->{reinstall},}}push@package,$package if$package;push@dist,$dist if$dist}return (\@package,\@dist,undef)}sub locate_dependency_file {my$self=shift;if (-f "cpm.yml"){return {type=>"cpmfile",path=>"cpm.yml" }}if (-f "cpanfile"){return {type=>"cpanfile",path=>"cpanfile" }}if (-f 'META.json'){my$meta=CPAN::Meta->load_file('META.json');if (!$meta->dynamic_config){return {type=>'metafile',path=>'META.json' }}}if (-f 'Build.PL' || -f 'Makefile.PL'){my$build_file= -f 'Build.PL' ? 'Build.PL' : 'Makefile.PL';warn "Executing $build_file to generate MYMETA.json and to determine requirements...\n";local%ENV=(PERL5_CPAN_IS_RUNNING=>1,PERL5_CPANPLUS_IS_RUNNING=>1,PERL5_CPANM_IS_RUNNING=>1,PERL_MM_USE_DEFAULT=>1,%ENV,);if (!$self->{global}){local$SIG{__WARN__}=sub {};local::lib->setup_env_hash_for($self->{local_lib},0)}my$runner=Command::Runner->new(command=>[$^X,$build_file ],timeout=>60,redirect=>1,);my$res=$runner->run;if ($res->{timeout}){die "Error: timed out (>60s).\n$res->{stdout}"}if ($res->{result}!=0){die "Error: failed to execute $build_file.\n$res->{stdout}"}if (!-f 'MYMETA.json'){die "Error: No MYMETA.json after executing $build_file\n"}return {type=>'metafile',path=>'MYMETA.json' }}return}sub load_dependency_file {my$self=shift;my$cpmfile=do {my ($type,$path)=@{$self->{dependency_file}}{qw(type path)};warn "Loading requirements from $path...\n";if ($type eq "cpmfile"){Module::cpmfile->load($path)}elsif ($type eq "cpanfile"){Module::cpmfile->from_cpanfile(Module::CPANfile->load($path))}elsif ($type eq "metafile"){Module::cpmfile->from_cpanmeta(CPAN::Meta->load_file($path))}else {die}};if (!$self->{mirror}){my$mirrors=$cpmfile->{_mirrors}|| [];if (@$mirrors){$self->{mirror}=$self->normalize_mirror($mirrors->[0])}else {$self->{mirror}=$self->{_default_mirror}}}my@phase=grep$self->{"with_$_"},qw(configure build test runtime develop);my@type=grep$self->{"with_$_"},qw(requires recommends suggests);my$reqs=$cpmfile->effective_requirements($self->{feature},\@phase,\@type);my (@package,@reinstall);for my$package (sort keys %$reqs){my$options=$reqs->{$package};my$req={package=>$package,version_range=>$options->{version},dev=>$options->{dev},reinstall=>$options->{git}? 1 : 0,};if ($options->{git}){push@reinstall,$req}else {push@package,$req}}require App::cpm::Resolver::Custom;my$resolver=App::cpm::Resolver::Custom->new(requirements=>$reqs,mirror=>$self->{mirror},from=>$self->{dependency_file}{type},);return (\@package,\@reinstall,$resolver->effective ? $resolver : undef)}sub generate_resolver {my ($self,$initial)=@_;my$cascade=App::cpm::Resolver::Cascade->new;$cascade->add($initial)if$initial;if (@{$self->{resolver}}){for my$r (@{$self->{resolver}}){my ($klass,@argv)=split /,/,$r;my$resolver=$self->_generate_resolver($klass,@argv);$cascade->add($resolver)}}return$cascade if!$self->{default_resolvers};if ($self->{mirror_only}){require App::cpm::Resolver::02Packages;my$resolver=App::cpm::Resolver::02Packages->new(mirror=>$self->{mirror},cache=>"$self->{home}/sources",);$cascade->add($resolver);return$cascade}if (!$self->{argv}and -f $self->{snapshot}){if (!eval {require App::cpm::Resolver::Snapshot}){die "To load $self->{snapshot}, you need to install Carton::Snapshot.\n"}warn "Loading distributions from $self->{snapshot}...\n";my$resolver=App::cpm::Resolver::Snapshot->new(path=>$self->{snapshot},mirror=>$self->{mirror},);$cascade->add($resolver)}my$resolver=App::cpm::Resolver::MetaCPAN->new($self->{dev}? (dev=>1): (only_dev=>1));$cascade->add($resolver);$resolver=App::cpm::Resolver::MetaDB->new(uri=>$self->{cpanmetadb},mirror=>$self->{mirror},);$cascade->add($resolver);if (!$self->{dev}){$resolver=App::cpm::Resolver::MetaCPAN->new;$cascade->add($resolver)}$cascade}sub _generate_resolver {my ($self,$klass,@argv)=@_;if ($klass =~ /^metadb$/i){my ($uri,$mirror);if (@argv > 1){($uri,$mirror)=@argv}elsif (@argv==1){$mirror=$argv[0]}else {$mirror=$self->{mirror}}return App::cpm::Resolver::MetaDB->new($uri ? (uri=>$uri): (),mirror=>$self->normalize_mirror($mirror),)}elsif ($klass =~ /^metacpan$/i){return App::cpm::Resolver::MetaCPAN->new(dev=>$self->{dev})}elsif ($klass =~ /^02packages?$/i){require App::cpm::Resolver::02Packages;my ($path,$mirror);if (@argv > 1){($path,$mirror)=@argv}elsif (@argv==1){$mirror=$argv[0]}else {$mirror=$self->{mirror}}return App::cpm::Resolver::02Packages->new($path ? (path=>$path): (),cache=>"$self->{home}/sources",mirror=>$self->normalize_mirror($mirror),)}elsif ($klass =~ /^snapshot$/i){require App::cpm::Resolver::Snapshot;return App::cpm::Resolver::Snapshot->new(path=>$self->{snapshot},mirror=>@argv ? $self->normalize_mirror($argv[0]): $self->{mirror},)}my$full_klass=$klass =~ s/^\+// ? $klass : "App::cpm::Resolver::$klass";(my$file=$full_klass)=~ s{::}{/}g;require "$file.pm";return$full_klass->new(@argv)}1; APP_CPM_CLI $fatpacked{"App/cpm/CircularDependency.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'APP_CPM_CIRCULARDEPENDENCY'; @@ -2594,11 +2594,11 @@ $fatpacked{"parent.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'PARENT'; PARENT $fatpacked{"version.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'VERSION'; - package version;use 5.006002;use strict;use warnings::register;if ($] >= 5.015){warnings::register_categories(qw/version/)}our$VERSION='0.9930';our$CLASS='version';our (@ISA,$STRICT,$LAX);{local$SIG{'__DIE__'};eval "use version::vxs $VERSION";if ($@){eval "use version::vpp $VERSION";die "$@" if ($@);push@ISA,"version::vpp";local $^W;*version::qv=\&version::vpp::qv;*version::declare=\&version::vpp::declare;*version::_VERSION=\&version::vpp::_VERSION;*version::vcmp=\&version::vpp::vcmp;*version::new=\&version::vpp::new;*version::numify=\&version::vpp::numify;*version::normal=\&version::vpp::normal;if ($] >= 5.009000){no strict 'refs';*version::stringify=\&version::vpp::stringify;*{'version::(""'}=\&version::vpp::stringify;*{'version::(<=>'}=\&version::vpp::vcmp;*{'version::(cmp'}=\&version::vpp::vcmp;*version::parse=\&version::vpp::parse}}else {push@ISA,"version::vxs";local $^W;*version::declare=\&version::vxs::declare;*version::qv=\&version::vxs::qv;*version::_VERSION=\&version::vxs::_VERSION;*version::vcmp=\&version::vxs::VCMP;*version::new=\&version::vxs::new;*version::numify=\&version::vxs::numify;*version::normal=\&version::vxs::normal;if ($] >= 5.009000){no strict 'refs';*version::stringify=\&version::vxs::stringify;*{'version::(""'}=\&version::vxs::stringify;*{'version::(<=>'}=\&version::vxs::VCMP;*{'version::(cmp'}=\&version::vxs::VCMP;*version::parse=\&version::vxs::parse}}}require version::regex;*version::is_lax=\&version::regex::is_lax;*version::is_strict=\&version::regex::is_strict;*LAX=\$version::regex::LAX;*LAX_DECIMAL_VERSION=\$version::regex::LAX_DECIMAL_VERSION;*LAX_DOTTED_DECIMAL_VERSION=\$version::regex::LAX_DOTTED_DECIMAL_VERSION;*STRICT=\$version::regex::STRICT;*STRICT_DECIMAL_VERSION=\$version::regex::STRICT_DECIMAL_VERSION;*STRICT_DOTTED_DECIMAL_VERSION=\$version::regex::STRICT_DOTTED_DECIMAL_VERSION;sub import {no strict 'refs';my ($class)=shift;unless ($class eq $CLASS){local $^W;*{$class.'::declare'}=\&{$CLASS.'::declare'};*{$class.'::qv'}=\&{$CLASS.'::qv'}}my%args;if (@_){map {$args{$_}=1}@_}else {%args=(qv=>1,'UNIVERSAL::VERSION'=>1,)}my$callpkg=caller();if (exists($args{declare})){*{$callpkg.'::declare'}=sub {return$class->declare(shift)}unless defined(&{$callpkg.'::declare'})}if (exists($args{qv})){*{$callpkg.'::qv'}=sub {return$class->qv(shift)}unless defined(&{$callpkg.'::qv'})}if (exists($args{'UNIVERSAL::VERSION'})){local $^W;*UNIVERSAL::VERSION=\&{$CLASS.'::_VERSION'}}if (exists($args{'VERSION'})){*{$callpkg.'::VERSION'}=\&{$CLASS.'::_VERSION'}}if (exists($args{'is_strict'})){*{$callpkg.'::is_strict'}=\&{$CLASS.'::is_strict'}unless defined(&{$callpkg.'::is_strict'})}if (exists($args{'is_lax'})){*{$callpkg.'::is_lax'}=\&{$CLASS.'::is_lax'}unless defined(&{$callpkg.'::is_lax'})}}1; + package version;use 5.006002;use strict;use warnings::register;if ($] >= 5.015){warnings::register_categories(qw/version/)}our$VERSION='0.9932';our$CLASS='version';our (@ISA,$STRICT,$LAX);{local$SIG{'__DIE__'};eval "use version::vxs $VERSION";if ($@){eval "use version::vpp $VERSION";die "$@" if ($@);push@ISA,"version::vpp";local $^W;*version::qv=\&version::vpp::qv;*version::declare=\&version::vpp::declare;*version::_VERSION=\&version::vpp::_VERSION;*version::vcmp=\&version::vpp::vcmp;*version::new=\&version::vpp::new;*version::numify=\&version::vpp::numify;*version::normal=\&version::vpp::normal;*version::to_decimal=\&version::vpp::to_decimal;*version::to_dotted_decimal=\&version::vpp::to_dotted_decimal;*version::tuple=\&version::vpp::tuple;*version::from_tuple=\&version::vpp::from_tuple;if ($] >= 5.009000){no strict 'refs';*version::stringify=\&version::vpp::stringify;*{'version::(""'}=\&version::vpp::stringify;*{'version::(<=>'}=\&version::vpp::vcmp;*{'version::(cmp'}=\&version::vpp::vcmp;*version::parse=\&version::vpp::parse}}else {push@ISA,"version::vxs";local $^W;*version::declare=\&version::vxs::declare;*version::qv=\&version::vxs::qv;*version::_VERSION=\&version::vxs::_VERSION;*version::vcmp=\&version::vxs::VCMP;*version::new=\&version::vxs::new;*version::numify=\&version::vxs::numify;*version::normal=\&version::vxs::normal;*version::to_decimal=\&version::vxs::to_decimal;*version::to_dotted_decimal=\&version::vxs::to_dotted_decimal;*version::tuple=\&version::vxs::tuple;*version::from_tuple=\&version::vxs::from_tuple;if ($] >= 5.009000){no strict 'refs';*version::stringify=\&version::vxs::stringify;*{'version::(""'}=\&version::vxs::stringify;*{'version::(<=>'}=\&version::vxs::VCMP;*{'version::(cmp'}=\&version::vxs::VCMP;*version::parse=\&version::vxs::parse}}}require version::regex;*version::is_lax=\&version::regex::is_lax;*version::is_strict=\&version::regex::is_strict;*LAX=\$version::regex::LAX;*LAX_DECIMAL_VERSION=\$version::regex::LAX_DECIMAL_VERSION;*LAX_DOTTED_DECIMAL_VERSION=\$version::regex::LAX_DOTTED_DECIMAL_VERSION;*STRICT=\$version::regex::STRICT;*STRICT_DECIMAL_VERSION=\$version::regex::STRICT_DECIMAL_VERSION;*STRICT_DOTTED_DECIMAL_VERSION=\$version::regex::STRICT_DOTTED_DECIMAL_VERSION;sub import {no strict 'refs';my ($class)=shift;unless ($class eq $CLASS){local $^W;*{$class.'::declare'}=\&{$CLASS.'::declare'};*{$class.'::qv'}=\&{$CLASS.'::qv'}}my%args;if (@_){map {$args{$_}=1}@_}else {%args=(qv=>1,'UNIVERSAL::VERSION'=>1,)}my$callpkg=caller();if (exists($args{declare})){*{$callpkg.'::declare'}=sub {return$class->declare(shift)}unless defined(&{$callpkg.'::declare'})}if (exists($args{qv})){*{$callpkg.'::qv'}=sub {return$class->qv(shift)}unless defined(&{$callpkg.'::qv'})}if (exists($args{'UNIVERSAL::VERSION'})){local $^W;*UNIVERSAL::VERSION=\&{$CLASS.'::_VERSION'}}if (exists($args{'VERSION'})){*{$callpkg.'::VERSION'}=\&{$CLASS.'::_VERSION'}}if (exists($args{'is_strict'})){*{$callpkg.'::is_strict'}=\&{$CLASS.'::is_strict'}unless defined(&{$callpkg.'::is_strict'})}if (exists($args{'is_lax'})){*{$callpkg.'::is_lax'}=\&{$CLASS.'::is_lax'}unless defined(&{$callpkg.'::is_lax'})}}1; VERSION $fatpacked{"version/regex.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'VERSION_REGEX'; - package version::regex;use strict;our$VERSION='0.9930';my$FRACTION_PART=qr/\.[0-9]+/;my$STRICT_INTEGER_PART=qr/0|[1-9][0-9]*/;my$LAX_INTEGER_PART=qr/[0-9]+/;my$STRICT_DOTTED_DECIMAL_PART=qr/\.[0-9]{1,3}/;my$LAX_DOTTED_DECIMAL_PART=qr/\.[0-9]+/;my$LAX_ALPHA_PART=qr/_[0-9]+/;our$STRICT_DECIMAL_VERSION=qr/ $STRICT_INTEGER_PART $FRACTION_PART? /x;our$STRICT_DOTTED_DECIMAL_VERSION=qr/ v $STRICT_INTEGER_PART $STRICT_DOTTED_DECIMAL_PART{2,} /x;our$STRICT=qr/ $STRICT_DECIMAL_VERSION | $STRICT_DOTTED_DECIMAL_VERSION /x;our$LAX_DECIMAL_VERSION=qr/ $LAX_INTEGER_PART (?: $FRACTION_PART | \. )? $LAX_ALPHA_PART? + package version::regex;use strict;our$VERSION='0.9932';my$FRACTION_PART=qr/\.[0-9]+/;my$STRICT_INTEGER_PART=qr/0|[1-9][0-9]*/;my$LAX_INTEGER_PART=qr/[0-9]+/;my$STRICT_DOTTED_DECIMAL_PART=qr/\.[0-9]{1,3}/;my$LAX_DOTTED_DECIMAL_PART=qr/\.[0-9]+/;my$LAX_ALPHA_PART=qr/_[0-9]+/;our$STRICT_DECIMAL_VERSION=qr/ $STRICT_INTEGER_PART $FRACTION_PART? /x;our$STRICT_DOTTED_DECIMAL_VERSION=qr/ v $STRICT_INTEGER_PART $STRICT_DOTTED_DECIMAL_PART{2,} /x;our$STRICT=qr/ $STRICT_DECIMAL_VERSION | $STRICT_DOTTED_DECIMAL_VERSION /x;our$LAX_DECIMAL_VERSION=qr/ $LAX_INTEGER_PART (?: $FRACTION_PART | \. )? $LAX_ALPHA_PART? | $FRACTION_PART $LAX_ALPHA_PART? /x;our$LAX_DOTTED_DECIMAL_VERSION=qr/ @@ -2609,7 +2609,7 @@ $fatpacked{"version/regex.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'V VERSION_REGEX $fatpacked{"version/vpp.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'VERSION_VPP'; - package charstar;use overload ('""'=>\&thischar,'0+'=>\&thischar,'++'=>\&increment,'--'=>\&decrement,'+'=>\&plus,'-'=>\&minus,'*'=>\&multiply,'cmp'=>\&cmp,'<=>'=>\&spaceship,'bool'=>\&thischar,'='=>\&clone,);sub new {my ($self,$string)=@_;my$class=ref($self)|| $self;my$obj={string=>[split(//,$string)],current=>0,};return bless$obj,$class}sub thischar {my ($self)=@_;my$last=$#{$self->{string}};my$curr=$self->{current};if ($curr >= 0 && $curr <= $last){return$self->{string}->[$curr]}else {return ''}}sub increment {my ($self)=@_;$self->{current}++}sub decrement {my ($self)=@_;$self->{current}--}sub plus {my ($self,$offset)=@_;my$rself=$self->clone;$rself->{current}+= $offset;return$rself}sub minus {my ($self,$offset)=@_;my$rself=$self->clone;$rself->{current}-= $offset;return$rself}sub multiply {my ($left,$right,$swapped)=@_;my$char=$left->thischar();return$char * $right}sub spaceship {my ($left,$right,$swapped)=@_;unless (ref($right)){$right=$left->new($right)}return$left->{current}<=> $right->{current}}sub cmp {my ($left,$right,$swapped)=@_;unless (ref($right)){if (length($right)==1){return$left->thischar cmp $right}$right=$left->new($right)}return$left->currstr cmp $right->currstr}sub bool {my ($self)=@_;my$char=$self->thischar;return ($char ne '')}sub clone {my ($left,$right,$swapped)=@_;$right={string=>[@{$left->{string}}],current=>$left->{current},};return bless$right,ref($left)}sub currstr {my ($self,$s)=@_;my$curr=$self->{current};my$last=$#{$self->{string}};if (defined($s)&& $s->{current}< $last){$last=$s->{current}}my$string=join('',@{$self->{string}}[$curr..$last]);return$string}package version::vpp;use 5.006002;use strict;use warnings::register;use Config;our$VERSION='0.9930';our$CLASS='version::vpp';our ($LAX,$STRICT,$WARN_CATEGORY);if ($] > 5.015){warnings::register_categories(qw/version/);$WARN_CATEGORY='version'}else {$WARN_CATEGORY='numeric'}require version::regex;*version::vpp::is_strict=\&version::regex::is_strict;*version::vpp::is_lax=\&version::regex::is_lax;*LAX=\$version::regex::LAX;*STRICT=\$version::regex::STRICT;use overload ('""'=>\&stringify,'0+'=>\&numify,'cmp'=>\&vcmp,'<=>'=>\&vcmp,'bool'=>\&vbool,'+'=>\&vnoop,'-'=>\&vnoop,'*'=>\&vnoop,'/'=>\&vnoop,'+='=>\&vnoop,'-='=>\&vnoop,'*='=>\&vnoop,'/='=>\&vnoop,'abs'=>\&vnoop,);sub import {no strict 'refs';my ($class)=shift;unless ($class eq $CLASS){local $^W;*{$class.'::declare'}=\&{$CLASS.'::declare'};*{$class.'::qv'}=\&{$CLASS.'::qv'}}my%args;if (@_){map {$args{$_}=1}@_}else {%args=(qv=>1,'UNIVERSAL::VERSION'=>1,)}my$callpkg=caller();if (exists($args{declare})){*{$callpkg.'::declare'}=sub {return$class->declare(shift)}unless defined(&{$callpkg.'::declare'})}if (exists($args{qv})){*{$callpkg.'::qv'}=sub {return$class->qv(shift)}unless defined(&{$callpkg.'::qv'})}if (exists($args{'UNIVERSAL::VERSION'})){no warnings qw/redefine/;*UNIVERSAL::VERSION=\&{$CLASS.'::_VERSION'}}if (exists($args{'VERSION'})){*{$callpkg.'::VERSION'}=\&{$CLASS.'::_VERSION'}}if (exists($args{'is_strict'})){*{$callpkg.'::is_strict'}=\&{$CLASS.'::is_strict'}unless defined(&{$callpkg.'::is_strict'})}if (exists($args{'is_lax'})){*{$callpkg.'::is_lax'}=\&{$CLASS.'::is_lax'}unless defined(&{$callpkg.'::is_lax'})}}my$VERSION_MAX=0x7FFFFFFF;use constant TRUE=>1;use constant FALSE=>0;sub isDIGIT {my ($char)=shift->thischar();return ($char =~ /\d/)}sub isALPHA {my ($char)=shift->thischar();return ($char =~ /[a-zA-Z]/)}sub isSPACE {my ($char)=shift->thischar();return ($char =~ /\s/)}sub BADVERSION {my ($s,$errstr,$error)=@_;if ($errstr){$$errstr=$error}return$s}sub prescan_version {my ($s,$strict,$errstr,$sqv,$ssaw_decimal,$swidth,$salpha)=@_;my$qv=defined$sqv ? $$sqv : FALSE;my$saw_decimal=defined$ssaw_decimal ? $$ssaw_decimal : 0;my$width=defined$swidth ? $$swidth : 3;my$alpha=defined$salpha ? $$salpha : FALSE;my$d=$s;if ($qv && isDIGIT($d)){goto dotted_decimal_version}if ($d eq 'v'){$d++;if (isDIGIT($d)){$qv=TRUE}else {return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)")}dotted_decimal_version: if ($strict && $d eq '0' && isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)")}while (isDIGIT($d)){$d++}if ($d eq '.'){$saw_decimal++;$d++}else {if ($strict){return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)")}else {goto version_prescan_finish}}{my$i=0;my$j=0;while (isDIGIT($d)){$i++;while (isDIGIT($d)){$d++;$j++;if ($strict && $j > 3){return BADVERSION($s,$errstr,"Invalid version format (maximum 3 digits between decimals)")}}if ($d eq '_'){if ($strict){return BADVERSION($s,$errstr,"Invalid version format (no underscores)")}if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)")}$d++;$alpha=TRUE}elsif ($d eq '.'){if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)")}$saw_decimal++;$d++}elsif (!isDIGIT($d)){last}$j=0}if ($strict && $i < 2){return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)")}}}else {my$j=0;if ($strict){if ($d eq '.'){return BADVERSION($s,$errstr,"Invalid version format (0 before decimal required)")}if ($d eq '0' && isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)")}}if ($d eq '-'){return BADVERSION($s,$errstr,"Invalid version format (negative version number)")}while (isDIGIT($d)){$d++}if ($d eq '.'){$saw_decimal++;$d++}elsif (!$d || $d eq ';' || isSPACE($d)|| $d eq '}'){if ($d==$s){return BADVERSION($s,$errstr,"Invalid version format (version required)")}goto version_prescan_finish}elsif ($d==$s){return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)")}elsif ($d eq '_'){if ($strict){return BADVERSION($s,$errstr,"Invalid version format (no underscores)")}elsif (isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (alpha without decimal)")}else {return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)")}}elsif ($d){return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)")}if ($d &&!isDIGIT($d)&& ($strict ||!($d eq ';' || isSPACE($d)|| $d eq '}'))){return BADVERSION($s,$errstr,"Invalid version format (fractional part required)")}while (isDIGIT($d)){$d++;$j++;if ($d eq '.' && isDIGIT($d-1)){if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)")}if ($strict){return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions must begin with 'v')")}$d=$s;$qv=TRUE;goto dotted_decimal_version}if ($d eq '_'){if ($strict){return BADVERSION($s,$errstr,"Invalid version format (no underscores)")}if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)")}if (!isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)")}$width=$j;$d++;$alpha=TRUE}}}version_prescan_finish: while (isSPACE($d)){$d++}if ($d &&!isDIGIT($d)&& (!($d eq ';' || $d eq '}'))){return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)")}if ($saw_decimal > 1 && ($d-1)eq '.'){return BADVERSION($s,$errstr,"Invalid version format (trailing decimal)")}if (defined$sqv){$$sqv=$qv}if (defined$swidth){$$swidth=$width}if (defined$ssaw_decimal){$$ssaw_decimal=$saw_decimal}if (defined$salpha){$$salpha=$alpha}return$d}sub scan_version {my ($s,$rv,$qv)=@_;my$start;my$pos;my$last;my$errstr;my$saw_decimal=0;my$width=3;my$alpha=FALSE;my$vinf=FALSE;my@av;$s=new charstar$s;while (isSPACE($s)){$s++}$last=prescan_version($s,FALSE,\$errstr,\$qv,\$saw_decimal,\$width,\$alpha);if ($errstr){if ($s ne 'undef'){require Carp;Carp::croak($errstr)}}$start=$s;if ($s eq 'v'){$s++}$pos=$s;if ($qv){$$rv->{qv}=$qv}if ($alpha){$$rv->{alpha}=$alpha}if (!$qv && $width < 3){$$rv->{width}=$width}while (isDIGIT($pos)|| $pos eq '_'){$pos++}if (!isALPHA($pos)){my$rev;for (;;){$rev=0;{my$end=$pos;my$mult=1;my$orev;if (!$qv && $s > $start && $saw_decimal==1){$mult *= 100;while ($s < $end){next if$s eq '_';$orev=$rev;$rev += $s * $mult;$mult /= 10;if ((abs($orev)> abs($rev))|| (abs($rev)> $VERSION_MAX)){warn("Integer overflow in version %d",$VERSION_MAX);$s=$end - 1;$rev=$VERSION_MAX;$vinf=1}$s++;if ($s eq '_'){$s++}}}else {while (--$end >= $s){next if$end eq '_';$orev=$rev;$rev += $end * $mult;$mult *= 10;if ((abs($orev)> abs($rev))|| (abs($rev)> $VERSION_MAX)){warn("Integer overflow in version");$end=$s - 1;$rev=$VERSION_MAX;$vinf=1}}}}push@av,$rev;if ($vinf){$s=$last;last}elsif ($pos eq '.'){$s= ++$pos}elsif ($pos eq '_' && isDIGIT($pos+1)){$s= ++$pos}elsif ($pos eq ',' && isDIGIT($pos+1)){$s= ++$pos}elsif (isDIGIT($pos)){$s=$pos}else {$s=$pos;last}if ($qv){while (isDIGIT($pos)|| $pos eq '_'){$pos++}}else {my$digits=0;while ((isDIGIT($pos)|| $pos eq '_')&& $digits < 3){if ($pos ne '_'){$digits++}$pos++}}}}if ($qv){my$len=$#av;$len=2 - $len;while ($len-- > 0){push@av,0}}if ($vinf){$$rv->{original}="v.Inf";$$rv->{vinf}=1}elsif ($s > $start){$$rv->{original}=$start->currstr($s);if ($qv && $saw_decimal==1 && $start ne 'v'){$$rv->{original}='v' .$$rv->{original}}}else {$$rv->{original}='0';push(@av,0)}$$rv->{version}=\@av;if ($s eq 'undef'){$s += 5}return$s}sub new {my$class=shift;unless (defined$class or $#_ > 1){require Carp;Carp::croak('Usage: version::new(class, version)')}my$self=bless ({},ref ($class)|| $class);my$qv=FALSE;if ($#_==1){$qv=TRUE}my$value=pop;if (ref($value)&& eval('$value->isa("version")')){$self->{version}=[@{$value->{version}}];$self->{qv}=1 if$value->{qv};$self->{alpha}=1 if$value->{alpha};$self->{original}=''.$value->{original};return$self}if (not defined$value or $value =~ /^undef$/){push @{$self->{version}},0;$self->{original}="0";return ($self)}if (ref($value)=~ m/ARRAY|HASH/){require Carp;Carp::croak("Invalid version format (non-numeric data)")}$value=_un_vstring($value);if ($Config{d_setlocale}){use POSIX qw/locale_h/;use if$Config{d_setlocale},'locale';my$currlocale=setlocale(LC_ALL);if (localeconv()->{decimal_point}eq ','){$value =~ tr/,/./}}if ($value =~ /\d+.?\d*e[-+]?\d+/){$value=sprintf("%.9f",$value);$value =~ s/(0+)$//}my$s=scan_version($value,\$self,$qv);if ($s){warn(sprintf "Version string '%s' contains invalid data; " ."ignoring: '%s'",$value,$s)}return ($self)}*parse=\&new;sub numify {my ($self)=@_;unless (_verify($self)){require Carp;Carp::croak("Invalid version object")}my$alpha=$self->{alpha}|| "";my$len=$#{$self->{version}};my$digit=$self->{version}[0];my$string=sprintf("%d.",$digit);if ($alpha and warnings::enabled()){warnings::warn($WARN_CATEGORY,'alpha->numify() is lossy')}for (my$i=1 ;$i <= $len ;$i++ ){$digit=$self->{version}[$i];$string .= sprintf("%03d",$digit)}if ($len==0){$string .= sprintf("000")}return$string}sub normal {my ($self)=@_;unless (_verify($self)){require Carp;Carp::croak("Invalid version object")}my$len=$#{$self->{version}};my$digit=$self->{version}[0];my$string=sprintf("v%d",$digit);for (my$i=1 ;$i <= $len ;$i++ ){$digit=$self->{version}[$i];$string .= sprintf(".%d",$digit)}if ($len <= 2){for ($len=2 - $len;$len!=0;$len-- ){$string .= sprintf(".%0d",0)}}return$string}sub stringify {my ($self)=@_;unless (_verify($self)){require Carp;Carp::croak("Invalid version object")}return exists$self->{original}? $self->{original}: exists$self->{qv}? $self->normal : $self->numify}sub vcmp {my ($left,$right,$swap)=@_;die "Usage: version::vcmp(lobj, robj, ...)" if @_ < 2;my$class=ref($left);unless (UNIVERSAL::isa($right,$class)){$right=$class->new($right)}if ($swap){($left,$right)=($right,$left)}unless (_verify($left)){require Carp;Carp::croak("Invalid version object")}unless (_verify($right)){require Carp;Carp::croak("Invalid version format")}my$l=$#{$left->{version}};my$r=$#{$right->{version}};my$m=$l < $r ? $l : $r;my$lalpha=$left->is_alpha;my$ralpha=$right->is_alpha;my$retval=0;my$i=0;while ($i <= $m && $retval==0){$retval=$left->{version}[$i]<=> $right->{version}[$i];$i++}if ($retval==0 && $l!=$r){if ($l < $r){while ($i <= $r && $retval==0){if ($right->{version}[$i]!=0){$retval=-1}$i++}}else {while ($i <= $l && $retval==0){if ($left->{version}[$i]!=0){$retval= +1}$i++}}}return$retval}sub vbool {my ($self)=@_;return vcmp($self,$self->new("0"),1)}sub vnoop {require Carp;Carp::croak("operation not supported with version object")}sub is_alpha {my ($self)=@_;return (exists$self->{alpha})}sub qv {my$value=shift;my$class=$CLASS;if (@_){$class=ref($value)|| $value;$value=shift}$value=_un_vstring($value);$value='v'.$value unless$value =~ /(^v|\d+\.\d+\.\d)/;my$obj=$CLASS->new($value);return bless$obj,$class}*declare=\&qv;sub is_qv {my ($self)=@_;return (exists$self->{qv})}sub _verify {my ($self)=@_;if (ref($self)&& eval {exists$self->{version}}&& ref($self->{version})eq 'ARRAY'){return 1}else {return 0}}sub _is_non_alphanumeric {my$s=shift;$s=new charstar$s;while ($s){return 0 if isSPACE($s);return 1 unless (isALPHA($s)|| isDIGIT($s)|| $s =~ /[.-]/);$s++}return 0}sub _un_vstring {my$value=shift;if (length($value)>= 1 && $value !~ /[,._]/ && _is_non_alphanumeric($value)){my$tvalue;if ($] >= 5.008_001){$tvalue=_find_magic_vstring($value);$value=$tvalue if length$tvalue}elsif ($] >= 5.006_000){$tvalue=sprintf("v%vd",$value);if ($tvalue =~ /^v\d+(\.\d+)*$/){$value=$tvalue}}}return$value}sub _find_magic_vstring {my$value=shift;my$tvalue='';require B;my$sv=B::svref_2object(\$value);my$magic=ref($sv)eq 'B::PVMG' ? $sv->MAGIC : undef;while ($magic){if ($magic->TYPE eq 'V'){$tvalue=$magic->PTR;$tvalue =~ s/^v?(.+)$/v$1/;last}else {$magic=$magic->MOREMAGIC}}$tvalue =~ tr/_//d;return$tvalue}sub _VERSION {my ($obj,$req)=@_;my$class=ref($obj)|| $obj;no strict 'refs';if (exists$INC{"$class.pm"}and not %{"$class\::"}and $] >= 5.008){require Carp;Carp::croak("$class defines neither package nor VERSION" ."--version check failed")}my$version=eval "\$$class\::VERSION";if (defined$version){local $^W if $] <= 5.008;$version=version::vpp->new($version)}if (defined$req){unless (defined$version){require Carp;my$msg=$] < 5.006 ? "$class version $req required--this is only version " : "$class does not define \$$class\::VERSION" ."--version check failed";if ($ENV{VERSION_DEBUG}){Carp::confess($msg)}else {Carp::croak($msg)}}$req=version::vpp->new($req);if ($req > $version){require Carp;if ($req->is_qv){Carp::croak(sprintf ("%s version %s required--"."this is only version %s",$class,$req->normal,$version->normal))}else {Carp::croak(sprintf ("%s version %s required--"."this is only version %s",$class,$req->stringify,$version->stringify))}}}return defined$version ? $version->stringify : undef}1; + package charstar;use overload ('""'=>\&thischar,'0+'=>\&thischar,'++'=>\&increment,'--'=>\&decrement,'+'=>\&plus,'-'=>\&minus,'*'=>\&multiply,'cmp'=>\&cmp,'<=>'=>\&spaceship,'bool'=>\&thischar,'='=>\&clone,);sub new {my ($self,$string)=@_;my$class=ref($self)|| $self;my$obj={string=>[split(//,$string)],current=>0,};return bless$obj,$class}sub thischar {my ($self)=@_;my$last=$#{$self->{string}};my$curr=$self->{current};if ($curr >= 0 && $curr <= $last){return$self->{string}->[$curr]}else {return ''}}sub increment {my ($self)=@_;$self->{current}++}sub decrement {my ($self)=@_;$self->{current}--}sub plus {my ($self,$offset)=@_;my$rself=$self->clone;$rself->{current}+= $offset;return$rself}sub minus {my ($self,$offset)=@_;my$rself=$self->clone;$rself->{current}-= $offset;return$rself}sub multiply {my ($left,$right,$swapped)=@_;my$char=$left->thischar();return$char * $right}sub spaceship {my ($left,$right,$swapped)=@_;unless (ref($right)){$right=$left->new($right)}return$left->{current}<=> $right->{current}}sub cmp {my ($left,$right,$swapped)=@_;unless (ref($right)){if (length($right)==1){return$left->thischar cmp $right}$right=$left->new($right)}return$left->currstr cmp $right->currstr}sub bool {my ($self)=@_;my$char=$self->thischar;return ($char ne '')}sub clone {my ($left,$right,$swapped)=@_;$right={string=>[@{$left->{string}}],current=>$left->{current},};return bless$right,ref($left)}sub currstr {my ($self,$s)=@_;my$curr=$self->{current};my$last=$#{$self->{string}};if (defined($s)&& $s->{current}< $last){$last=$s->{current}}my$string=join('',@{$self->{string}}[$curr..$last]);return$string}package version::vpp;use 5.006002;use strict;use warnings::register;use Config;our$VERSION='0.9932';our$CLASS='version::vpp';our ($LAX,$STRICT,$WARN_CATEGORY);if ($] > 5.015){warnings::register_categories(qw/version/);$WARN_CATEGORY='version'}else {$WARN_CATEGORY='numeric'}require version::regex;*version::vpp::is_strict=\&version::regex::is_strict;*version::vpp::is_lax=\&version::regex::is_lax;*LAX=\$version::regex::LAX;*STRICT=\$version::regex::STRICT;use overload ('""'=>\&stringify,'0+'=>\&numify,'cmp'=>\&vcmp,'<=>'=>\&vcmp,'bool'=>\&vbool,'+'=>\&vnoop,'-'=>\&vnoop,'*'=>\&vnoop,'/'=>\&vnoop,'+='=>\&vnoop,'-='=>\&vnoop,'*='=>\&vnoop,'/='=>\&vnoop,'abs'=>\&vnoop,);sub import {no strict 'refs';my ($class)=shift;unless ($class eq $CLASS){local $^W;*{$class.'::declare'}=\&{$CLASS.'::declare'};*{$class.'::qv'}=\&{$CLASS.'::qv'}}my%args;if (@_){map {$args{$_}=1}@_}else {%args=(qv=>1,'UNIVERSAL::VERSION'=>1,)}my$callpkg=caller();if (exists($args{declare})){*{$callpkg.'::declare'}=sub {return$class->declare(shift)}unless defined(&{$callpkg.'::declare'})}if (exists($args{qv})){*{$callpkg.'::qv'}=sub {return$class->qv(shift)}unless defined(&{$callpkg.'::qv'})}if (exists($args{'UNIVERSAL::VERSION'})){no warnings qw/redefine/;*UNIVERSAL::VERSION=\&{$CLASS.'::_VERSION'}}if (exists($args{'VERSION'})){*{$callpkg.'::VERSION'}=\&{$CLASS.'::_VERSION'}}if (exists($args{'is_strict'})){*{$callpkg.'::is_strict'}=\&{$CLASS.'::is_strict'}unless defined(&{$callpkg.'::is_strict'})}if (exists($args{'is_lax'})){*{$callpkg.'::is_lax'}=\&{$CLASS.'::is_lax'}unless defined(&{$callpkg.'::is_lax'})}}my$VERSION_MAX=0x7FFFFFFF;use constant TRUE=>1;use constant FALSE=>0;sub isDIGIT {my ($char)=shift->thischar();return ($char =~ /\d/)}sub isALPHA {my ($char)=shift->thischar();return ($char =~ /[a-zA-Z]/)}sub isSPACE {my ($char)=shift->thischar();return ($char =~ /\s/)}sub BADVERSION {my ($s,$errstr,$error)=@_;if ($errstr){$$errstr=$error}return$s}sub prescan_version {my ($s,$strict,$errstr,$sqv,$ssaw_decimal,$swidth,$salpha)=@_;my$qv=defined$sqv ? $$sqv : FALSE;my$saw_decimal=defined$ssaw_decimal ? $$ssaw_decimal : 0;my$width=defined$swidth ? $$swidth : 3;my$alpha=defined$salpha ? $$salpha : FALSE;my$d=$s;if ($qv && isDIGIT($d)){goto dotted_decimal_version}if ($d eq 'v'){$d++;if (isDIGIT($d)){$qv=TRUE}else {return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)")}dotted_decimal_version: if ($strict && $d eq '0' && isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)")}while (isDIGIT($d)){$d++}if ($d eq '.'){$saw_decimal++;$d++}else {if ($strict){return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)")}else {goto version_prescan_finish}}{my$i=0;my$j=0;while (isDIGIT($d)){$i++;while (isDIGIT($d)){$d++;$j++;if ($strict && $j > 3){return BADVERSION($s,$errstr,"Invalid version format (maximum 3 digits between decimals)")}}if ($d eq '_'){if ($strict){return BADVERSION($s,$errstr,"Invalid version format (no underscores)")}if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)")}$d++;$alpha=TRUE}elsif ($d eq '.'){if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)")}$saw_decimal++;$d++}elsif (!isDIGIT($d)){last}$j=0}if ($strict && $i < 2){return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)")}}}else {my$j=0;if ($strict){if ($d eq '.'){return BADVERSION($s,$errstr,"Invalid version format (0 before decimal required)")}if ($d eq '0' && isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)")}}if ($d eq '-'){return BADVERSION($s,$errstr,"Invalid version format (negative version number)")}while (isDIGIT($d)){$d++}if ($d eq '.'){$saw_decimal++;$d++}elsif (!$d || $d eq ';' || isSPACE($d)|| $d eq '}'){if ($d==$s){return BADVERSION($s,$errstr,"Invalid version format (version required)")}goto version_prescan_finish}elsif ($d==$s){return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)")}elsif ($d eq '_'){if ($strict){return BADVERSION($s,$errstr,"Invalid version format (no underscores)")}elsif (isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (alpha without decimal)")}else {return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)")}}elsif ($d){return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)")}if ($d &&!isDIGIT($d)&& ($strict ||!($d eq ';' || isSPACE($d)|| $d eq '}'))){return BADVERSION($s,$errstr,"Invalid version format (fractional part required)")}while (isDIGIT($d)){$d++;$j++;if ($d eq '.' && isDIGIT($d-1)){if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)")}if ($strict){return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions must begin with 'v')")}$d=$s;$qv=TRUE;goto dotted_decimal_version}if ($d eq '_'){if ($strict){return BADVERSION($s,$errstr,"Invalid version format (no underscores)")}if ($alpha){return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)")}if (!isDIGIT($d+1)){return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)")}$width=$j;$d++;$alpha=TRUE}}}version_prescan_finish: while (isSPACE($d)){$d++}if ($d &&!isDIGIT($d)&& (!($d eq ';' || $d eq '}'))){return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)")}if ($saw_decimal > 1 && ($d-1)eq '.'){return BADVERSION($s,$errstr,"Invalid version format (trailing decimal)")}if (defined$sqv){$$sqv=$qv}if (defined$swidth){$$swidth=$width}if (defined$ssaw_decimal){$$ssaw_decimal=$saw_decimal}if (defined$salpha){$$salpha=$alpha}return$d}sub scan_version {my ($s,$rv,$qv)=@_;my$start;my$pos;my$last;my$errstr;my$saw_decimal=0;my$width=3;my$alpha=FALSE;my$vinf=FALSE;my@av;$s=new charstar$s;while (isSPACE($s)){$s++}$last=prescan_version($s,FALSE,\$errstr,\$qv,\$saw_decimal,\$width,\$alpha);if ($errstr){if ($s ne 'undef'){require Carp;Carp::croak($errstr)}}$start=$s;if ($s eq 'v'){$s++}$pos=$s;if ($qv){$$rv->{qv}=$qv}if ($alpha){$$rv->{alpha}=$alpha}if (!$qv && $width < 3){$$rv->{width}=$width}while (isDIGIT($pos)|| $pos eq '_'){$pos++}if (!isALPHA($pos)){my$rev;for (;;){$rev=0;{my$end=$pos;my$mult=1;my$orev;if (!$qv && $s > $start && $saw_decimal==1){$mult *= 100;while ($s < $end){next if$s eq '_';$orev=$rev;$rev += $s * $mult;$mult /= 10;if ((abs($orev)> abs($rev))|| (abs($rev)> $VERSION_MAX)){warn("Integer overflow in version %d",$VERSION_MAX);$s=$end - 1;$rev=$VERSION_MAX;$vinf=1}$s++;if ($s eq '_'){$s++}}}else {while (--$end >= $s){next if$end eq '_';$orev=$rev;$rev += $end * $mult;$mult *= 10;if ((abs($orev)> abs($rev))|| (abs($rev)> $VERSION_MAX)){warn("Integer overflow in version");$end=$s - 1;$rev=$VERSION_MAX;$vinf=1}}}}push@av,$rev;if ($vinf){$s=$last;last}elsif ($pos eq '.'){$s= ++$pos}elsif ($pos eq '_' && isDIGIT($pos+1)){$s= ++$pos}elsif ($pos eq ',' && isDIGIT($pos+1)){$s= ++$pos}elsif (isDIGIT($pos)){$s=$pos}else {$s=$pos;last}if ($qv){while (isDIGIT($pos)|| $pos eq '_'){$pos++}}else {my$digits=0;while ((isDIGIT($pos)|| $pos eq '_')&& $digits < 3){if ($pos ne '_'){$digits++}$pos++}}}}if ($qv){my$len=$#av;$len=2 - $len;while ($len-- > 0){push@av,0}}if ($vinf){$$rv->{original}="v.Inf";$$rv->{vinf}=1}elsif ($s > $start){$$rv->{original}=$start->currstr($s);if ($qv && $saw_decimal==1 && $start ne 'v'){$$rv->{original}='v' .$$rv->{original}}}else {$$rv->{original}='0';push(@av,0)}$$rv->{version}=\@av;if ($s eq 'undef'){$s += 5}return$s}sub new {my$class=shift;unless (defined$class or $#_ > 1){require Carp;Carp::croak('Usage: version::new(class, version)')}my$self=bless ({},ref ($class)|| $class);my$qv=FALSE;if ($#_==1){$qv=TRUE}my$value=pop;if (ref($value)&& eval('$value->isa("version")')){$self->{version}=[@{$value->{version}}];$self->{qv}=1 if$value->{qv};$self->{alpha}=1 if$value->{alpha};$self->{original}=''.$value->{original};return$self}if (not defined$value or $value =~ /^undef$/){push @{$self->{version}},0;$self->{original}="0";return ($self)}if (ref($value)=~ m/ARRAY|HASH/){require Carp;Carp::croak("Invalid version format (non-numeric data)")}$value=_un_vstring($value);if ($Config{d_setlocale}){use POSIX qw/locale_h/;use if$Config{d_setlocale},'locale';my$currlocale=setlocale(LC_ALL);if (localeconv()->{decimal_point}eq ','){$value =~ tr/,/./}}if ($value =~ /\d+.?\d*e[-+]?\d+/){$value=sprintf("%.9f",$value);$value =~ s/(0+)$//}my$s=scan_version($value,\$self,$qv);if ($s){warn(sprintf "Version string '%s' contains invalid data; " ."ignoring: '%s'",$value,$s)}return ($self)}*parse=\&new;sub numify {my ($self)=@_;unless (_verify($self)){require Carp;Carp::croak("Invalid version object")}my$alpha=$self->{alpha}|| "";my$len=$#{$self->{version}};my$digit=$self->{version}[0];my$string=sprintf("%d.",$digit);if ($alpha and warnings::enabled()){warnings::warn($WARN_CATEGORY,'alpha->numify() is lossy')}for (my$i=1 ;$i <= $len ;$i++ ){$digit=$self->{version}[$i];$string .= sprintf("%03d",$digit)}if ($len==0){$string .= sprintf("000")}return$string}sub normal {my ($self)=@_;unless (_verify($self)){require Carp;Carp::croak("Invalid version object")}my$len=$#{$self->{version}};my$digit=$self->{version}[0];my$string=sprintf("v%d",$digit);for (my$i=1 ;$i <= $len ;$i++ ){$digit=$self->{version}[$i];$string .= sprintf(".%d",$digit)}if ($len <= 2){for ($len=2 - $len;$len!=0;$len-- ){$string .= sprintf(".%0d",0)}}return$string}sub stringify {my ($self)=@_;unless (_verify($self)){require Carp;Carp::croak("Invalid version object")}return exists$self->{original}? $self->{original}: exists$self->{qv}? $self->normal : $self->numify}sub to_decimal {my ($self)=@_;return ref($self)->new($self->numify)}sub to_dotted_decimal {my ($self)=@_;return ref($self)->new($self->normal)}sub vcmp {my ($left,$right,$swap)=@_;die "Usage: version::vcmp(lobj, robj, ...)" if @_ < 2;my$class=ref($left);unless (UNIVERSAL::isa($right,$class)){$right=$class->new($right)}if ($swap){($left,$right)=($right,$left)}unless (_verify($left)){require Carp;Carp::croak("Invalid version object")}unless (_verify($right)){require Carp;Carp::croak("Invalid version format")}my$l=$#{$left->{version}};my$r=$#{$right->{version}};my$m=$l < $r ? $l : $r;my$lalpha=$left->is_alpha;my$ralpha=$right->is_alpha;my$retval=0;my$i=0;while ($i <= $m && $retval==0){$retval=$left->{version}[$i]<=> $right->{version}[$i];$i++}if ($retval==0 && $l!=$r){if ($l < $r){while ($i <= $r && $retval==0){if ($right->{version}[$i]!=0){$retval=-1}$i++}}else {while ($i <= $l && $retval==0){if ($left->{version}[$i]!=0){$retval= +1}$i++}}}return$retval}sub vbool {my ($self)=@_;return vcmp($self,$self->new("0"),1)}sub vnoop {require Carp;Carp::croak("operation not supported with version object")}sub is_alpha {my ($self)=@_;return (exists$self->{alpha})}sub qv {my$value=shift;my$class=$CLASS;if (@_){$class=ref($value)|| $value;$value=shift}$value=_un_vstring($value);$value='v'.$value unless$value =~ /(^v|\d+\.\d+\.\d)/;my$obj=$CLASS->new($value);return bless$obj,$class}*declare=\&qv;sub is_qv {my ($self)=@_;return (exists$self->{qv})}sub tuple {my ($self)=@_;return @{$self->{version}}}sub from_tuple {my ($proto,@args)=@_;my$class=ref($proto)|| $proto;my@version=map 0+$_,@args;die if@args < 1;return bless {version=>\@version,qv=>!!1,'v' .join('.',@version),},$class}sub _verify {my ($self)=@_;if (ref($self)&& eval {exists$self->{version}}&& ref($self->{version})eq 'ARRAY'){return 1}else {return 0}}sub _is_non_alphanumeric {my$s=shift;$s=new charstar$s;while ($s){return 0 if isSPACE($s);return 1 unless (isALPHA($s)|| isDIGIT($s)|| $s =~ /[.-]/);$s++}return 0}sub _un_vstring {my$value=shift;if (length($value)>= 1 && $value !~ /[,._]/ && _is_non_alphanumeric($value)){my$tvalue;if ($] >= 5.008_001){$tvalue=_find_magic_vstring($value);$value=$tvalue if length$tvalue}elsif ($] >= 5.006_000){$tvalue=sprintf("v%vd",$value);if ($tvalue =~ /^v\d+(\.\d+)*$/){$value=$tvalue}}}return$value}sub _find_magic_vstring {my$value=shift;my$tvalue='';require B;my$sv=B::svref_2object(\$value);my$magic=ref($sv)eq 'B::PVMG' ? $sv->MAGIC : undef;while ($magic){if ($magic->TYPE eq 'V'){$tvalue=$magic->PTR;$tvalue =~ s/^v?(.+)$/v$1/;last}else {$magic=$magic->MOREMAGIC}}$tvalue =~ tr/_//d;return$tvalue}sub _VERSION {my ($obj,$req)=@_;my$class=ref($obj)|| $obj;no strict 'refs';if (exists$INC{"$class.pm"}and not %{"$class\::"}and $] >= 5.008){require Carp;Carp::croak("$class defines neither package nor VERSION" ."--version check failed")}my$version=eval "\$$class\::VERSION";if (defined$version){local $^W if $] <= 5.008;$version=version::vpp->new($version)}if (defined$req){unless (defined$version){require Carp;my$msg=$] < 5.006 ? "$class version $req required--this is only version " : "$class does not define \$$class\::VERSION" ."--version check failed";if ($ENV{VERSION_DEBUG}){Carp::confess($msg)}else {Carp::croak($msg)}}$req=version::vpp->new($req);if ($req > $version){require Carp;if ($req->is_qv){Carp::croak(sprintf ("%s version %s required--"."this is only version %s",$class,$req->normal,$version->normal))}else {Carp::croak(sprintf ("%s version %s required--"."this is only version %s",$class,$req->stringify,$version->stringify))}}}return defined$version ? $version->stringify : undef}1; VERSION_VPP s/^ //mg for values %fatpacked; @@ -2706,7 +2706,8 @@ cpm - a fast CPAN module installer verbose mode; you can see what is going on --prebuilt, --no-prebuilt save builds for CPAN distributions; and later, install the prebuilts if available - default: on; you can also set $ENV{PERL_CPM_PREBUILT} false to disable this option + default: on; you can also set $ENV{PERL_CPM_PREBUILT} false to disable this option. + usage of --test and/or --man-pages disables this option. --target-perl=VERSION (EXPERIMENTAL) install modules as if version is your perl is VERSION --mirror=URL