From b3723347b2a4f9818f063f657d7088c4077c2281 Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 08:19:11 +0200 Subject: [PATCH 1/9] Add a simple blacklisting mechanism Some modules are detected as dependencies due to looking in tests. This patch blacklists some common 'false positives' --- cpanspec | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpanspec b/cpanspec index e77b2c4..ebda354 100755 --- a/cpanspec +++ b/cpanspec @@ -260,6 +260,15 @@ my @MACROS = ( # this is set after the parameters are passed our %macro; +our %dep_blacklist = ( + 'Win32' => 1, # We're not on win32 + 'Win32::Process' => 1, # We're not on win32 + 'Test::Perl::Critic' => 1, # Too many dependencies + 'ok' => 1, # Side effect of Test::use::ok + 'BaseClass' => 1, # Common test class shipped by ourselves + 'TestServer' => 1, # Likewise +); + sub print_version { print "$NAME version $VERSION\n"; exit 0; @@ -1005,6 +1014,7 @@ END } for my $dep (sort(keys(%build_requires))) { + next if exists $dep_blacklist{$dep}; if (exists($corelist{$dep})) { next if (!$compat); } elsif ($follow) { From a84c2839ce2137d1d9c5d28bd468c578fb3ea1ff Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 09:23:00 +0200 Subject: [PATCH 2/9] Don't let Module::AutoInstall run interactively --- cpanspec | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cpanspec b/cpanspec index ebda354..4ed8188 100755 --- a/cpanspec +++ b/cpanspec @@ -819,6 +819,7 @@ for my $file (@args) { # TODO It's possible these need to be listed instead of just detected. my $scripts=(grep /^(?:bin|scripts)\//, @files); + my $uses_autoinstall = grep /Module\/AutoInstall.pm/, @files; my (%build_requires,%requires); my ($yml,$meta); if (grep /^META\.yml$/, @files @@ -1115,6 +1116,12 @@ END \%build END + if($uses_autoinstall) { + print $spec < Date: Fri, 19 Aug 2011 08:21:22 +0200 Subject: [PATCH 3/9] Detect scripts better cpanspec tries to detect when scripts will be installed, so it can add man1 and bindir entries to %files. This patch adds some more heuristics to detect more cases of scri[ts being installed. --- cpanspec | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cpanspec b/cpanspec index 4ed8188..57058b9 100755 --- a/cpanspec +++ b/cpanspec @@ -818,8 +818,18 @@ for my $file (@args) { my $license=""; # TODO It's possible these need to be listed instead of just detected. - my $scripts=(grep /^(?:bin|scripts)\//, @files); my $uses_autoinstall = grep /Module\/AutoInstall.pm/, @files; + my $scripts=(grep /^(?:bin|scripts?|tools)\//, @files); + my $makecontent; + if (grep /^Makefile\.PL$/, @files + and $makecontent=extract($archive, $type, "$path/Makefile.PL")) { + $scripts ||= $makecontent =~ 'install_script'; + $scripts ||= ($makecontent =~ /EXE_FILES/ && $makecontent !~ /EXE_FILES.*\[\s*(qw\(\s*\)\s*)?\]/) ? 1 : 0; + } + if (grep /^Build\.PL$/, @files + and $makecontent=extract($archive, $type, "$path/Build.PL")) { + $scripts ||= $makecontent =~ 'script_files'; + } my (%build_requires,%requires); my ($yml,$meta); if (grep /^META\.yml$/, @files From 5516e78b17fb106d95890984dec4c0bcdd043771 Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 08:22:45 +0200 Subject: [PATCH 4/9] Add entries from configure_requres in META.yml as build dependencies --- cpanspec | 1 + 1 file changed, 1 insertion(+) diff --git a/cpanspec b/cpanspec index 57058b9..8e9334a 100755 --- a/cpanspec +++ b/cpanspec @@ -843,6 +843,7 @@ for my $file (@args) { } %build_requires=%{$meta->{build_requires}} if ($meta->{build_requires}); + %build_requires=(%build_requires, %{$meta->{configure_requires}}) if ($meta->{configure_requires}); %requires=%{$meta->{requires}} if ($meta->{requires}); if ($meta->{recommends}) { for my $dep (keys(%{$meta->{recommends}})) { From c406955800472398c0105c72f46ba5b73ade5597 Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 08:23:50 +0200 Subject: [PATCH 5/9] Strip any version comparison operator from the 'perl' build requirement Because cpanspec does things with the epoch, and already adds version comparison operators itself, they should be stripped from whatever META.yml specifies so cpanspec does not generate invalid spec files. --- cpanspec | 1 + 1 file changed, 1 insertion(+) diff --git a/cpanspec b/cpanspec index 8e9334a..f7fc1fc 100755 --- a/cpanspec +++ b/cpanspec @@ -1015,6 +1015,7 @@ END } if (defined($build_requires{perl})) { + $build_requires{perl} =~ s/^[<>=]+ *//; printf $spec "%-16s%s >= %s\n", "BuildRequires:", "perl", (($build_requires{perl} lt "5.6.0" ? "0:" : "1:") . $build_requires{perl}) if $build_requires{perl}; From 28dc8e9339e21b847b4b10f74ba74386dee7d7ed Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 08:57:07 +0200 Subject: [PATCH 6/9] Stop losing dependency version information cpanspec would unconditionally set the version requirement to 0 for Module::Build, ExtUtils::MakeMaker and dependencies detected in tests. This is not correct if the module already has specified a versioned dependency. --- cpanspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpanspec b/cpanspec index f7fc1fc..475cd0a 100755 --- a/cpanspec +++ b/cpanspec @@ -922,16 +922,16 @@ for my $file (@args) { #print STDERR "$testfile: @{[$extract_o_matic->array()]}\n"; for my $dep ($extract_o_matic->array()) { next if ($dep eq $module); - $build_requires{$dep}=0; + $build_requires{$dep} ||= 0; } } my $usebuildpl=0; if (grep /^Build\.PL$/, @files) { - $build_requires{'Module::Build'}=0; + $build_requires{'Module::Build'} ||= 0; $usebuildpl=1; } else { - $build_requires{'ExtUtils::MakeMaker'}=0; + $build_requires{'ExtUtils::MakeMaker'} ||= 0; } if (!$usebuildpl) { From 1cd8735b7cb9e73853082a70e9463bd87da59209 Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 08:58:10 +0200 Subject: [PATCH 7/9] Check all build requirements against CPAN - If a module is provided by ourselves: don't add a build dependency - If a module does not exist on CPAN: don't add a build dependency. It is most likely a module shipped by the module itself to support tests --- cpanspec | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/cpanspec b/cpanspec index 475cd0a..37249d8 100755 --- a/cpanspec +++ b/cpanspec @@ -586,6 +586,12 @@ while (my $provides=<$rpm>) { my @args=@ARGV; my @processed=(); +update_packages(); +$packages=Parse::CPAN::Packages->new($pkgdetails) + if (!defined($packages)); +die "Parse::CPAN::Packages->new() failed: $!\n" + if (!defined($packages)); + for my $file (@args) { my ($name,$version,$type); @@ -607,11 +613,6 @@ for my $file (@args) { $file =~ s/-/::/g; # Look up $file in 02packages.details.txt. - update_packages(); - $packages=Parse::CPAN::Packages->new($pkgdetails) - if (!defined($packages)); - die "Parse::CPAN::Packages->new() failed: $!\n" - if (!defined($packages)); my ($m,$d); if ($m=$packages->package($file) and $d=$m->distribution()) { $source=$cpan . "/authors/id/" . $d->prefix(); @@ -922,6 +923,19 @@ for my $file (@args) { #print STDERR "$testfile: @{[$extract_o_matic->array()]}\n"; for my $dep ($extract_o_matic->array()) { next if ($dep eq $module); + next if exists $build_requires{$dep}; + my $package = $packages->package($dep); + if(!defined($package)) { + # Don't print this for common false positives + unless($dep =~ /^(Config|base|5|lib)/) { + print STDERR "Module not on CPAN, not adding dependency: $dep\n"; + } + next; + } + if($package->distribution->dist eq $name) { + print STDERR "Dependency $dep provided by ourselves, not adding dependency\n"; + next; + } $build_requires{$dep} ||= 0; } } From 3b953c0923fe88176aa65ba3873611b2a58dcdaf Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Fri, 19 Aug 2011 09:09:10 +0200 Subject: [PATCH 8/9] Allow building rpms for slightly older perl versions The --old version is a bit of a harsh measure when merely building specfiles for centos 4 (perl 5.8.5) rpms on centos 5 (perl 5.8.8). This patch allows you to specify a minimum version to support and will use Module::Corelist instead of rpm to generate the corelist for that version. --- cpanspec | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/cpanspec b/cpanspec index 37249d8..c938e74 100755 --- a/cpanspec +++ b/cpanspec @@ -26,6 +26,7 @@ cpanspec [options] [file [...]] Options: --help -h Help message --old -o Be more compatible with old RHL/FC releases + --perl-version -P Minimum perl version to support --license -l Include generated license texts if absent in source --noprefix -n Don't add perl- prefix to package name --force -f Force overwriting existing spec @@ -86,6 +87,11 @@ Includes a hack to remove LD_RUN_PATH from Makefile. =back +=item B<-P>, B<--perl-version> + +Include explicit dependencies for core modules when newer versions are +required than shipped with the specified version. + =item B<-l>, B<--license> Generate COPYING and Artistic license texts if the source doesn't seem @@ -204,6 +210,7 @@ use File::Basename; use LWP::UserAgent; use Parse::CPAN::Packages; use Pod::Simple::TextContent; +use Module::CoreList; # Apparently gets pulled in by another module. #use Cwd; @@ -211,6 +218,7 @@ our %opt; our $help=0; our $compat=0; +our $perl_version=0; our $addlicense=0; our $noprefix=0; our $force=0; @@ -527,6 +535,7 @@ setlocale(LC_ALL, "en_US.UTF-8"); GetOptions( 'help|h' => \$help, 'old|o' => \$compat, + 'perl-version|P=s' => \$perl_version, 'license|l' => \$addlicense, 'noprefix|n' => \$noprefix, 'force|f' => \$force, @@ -572,14 +581,21 @@ if (!$packager or $packager eq "\%packager") { our %corelist; -my $rpm=new FileHandle "rpm -q --provides perl|" - or warn "Failed to execute rpm: $!\n"; +if($perl_version) { + die("Unknown perl version: $perl_version. (Known versions: " . join(", ", keys %Module::CoreList::version) . ")") + unless exists $Module::CoreList::version{$perl_version}; + %corelist = %{ $Module::CoreList::version{$perl_version} }; +} +else { + my $rpm=new FileHandle "rpm -q --provides perl|" + or warn "Failed to execute rpm: $!\n"; -while (my $provides=<$rpm>) { - chomp $provides; + while (my $provides=<$rpm>) { + chomp $provides; - if ($provides=~/^perl\(([^\)]+)\)(?:\s+=\s+(\S+))\s*$/) { - $corelist{$1}=defined($2) ? $2 : 0; + if ($provides=~/^perl\(([^\)]+)\)(?:\s+=\s+(\S+))\s*$/) { + $corelist{$1}=defined($2) ? $2 : 0; + } } } @@ -1042,7 +1058,7 @@ END for my $dep (sort(keys(%build_requires))) { next if exists $dep_blacklist{$dep}; - if (exists($corelist{$dep})) { + if (exists($corelist{$dep}) && $corelist{$dep} ge $build_requires{$dep}) { next if (!$compat); } elsif ($follow) { if ($dep ne $module and !(grep { $_ eq $dep } @processed, @args)) { From 2c6340efb09a38fa5c29c17ad564e7426520203e Mon Sep 17 00:00:00 2001 From: Dennis Kaarsemaker Date: Wed, 31 Aug 2011 18:32:24 +0200 Subject: [PATCH 9/9] Add an option to print the generated specfile to stdout This is useful when you want to postprocess the generated specfile in some way. We use this in our build system to merge in old changelogs and customizations. --- cpanspec | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cpanspec b/cpanspec index c938e74..0cae552 100755 --- a/cpanspec +++ b/cpanspec @@ -109,6 +109,10 @@ Force overwriting an existing spec file. Normally B will refuse to overwrite an existing spec file for safety. This option removes that safety check. Please use with caution. +=item B<-S>, B<--stdout> + +Write the generated spec file to stdout instead of a file. + =item B<-p>, B<--packager> The name and email address of the packager. Overrides the C<%packager> @@ -222,6 +226,7 @@ our $perl_version=0; our $addlicense=0; our $noprefix=0; our $force=0; +our $stdout=0; our $packager; our $release=1; our $epoch; @@ -539,6 +544,7 @@ GetOptions( 'license|l' => \$addlicense, 'noprefix|n' => \$noprefix, 'force|f' => \$force, + 'stdout|S' => \$stdout, 'packager|p=s' => \$packager, 'release|r=i' => \$release, 'epoch|e=i' => \$epoch, @@ -817,7 +823,9 @@ for my $file (@args) { verbose "Writing $specfile..."; my $spec; - if ($force) { + if ($stdout) { + $spec = *STDOUT; + } elsif ($force) { rename($specfile, "$specfile~") if (-e $specfile); $spec=new FileHandle ">$specfile"; } else {