Created
February 6, 2009 10:18
-
-
Save mizzy/59314 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
use Getopt::Long; | |
use LWP::Simple; | |
use File::Temp qw(tempdir); | |
use Archive::Tar; | |
use YAML; | |
use IPC::Run3; | |
my @doc_modules = qw( Catalyst::Manual ); | |
my %use_module_mapping = ( | |
'Module::Install' => 'inc::Module::Install', | |
); | |
GetOptions( | |
\my %options, "outdir=s", "tmpdir=s", "email=s", "name|n=s", "create", | |
"test|t", "epoch|e=n", "version|v=s", "release|r=s", "patch=s@", | |
"noarch", "arch|a=s", "noperlreqs", "usage", "buildall|b", "installdirs=s", | |
"descfile=s", "help", "requires=s@", "buildrequires=s@", "sign", "post=s", | |
"pre=s", "preun=s", "postun=s", "just-spec|j", 'use-usr-local', 'packager', | |
); | |
my $module = shift; | |
my $log_level = $options{'log-level'} || 'info'; | |
my $tmpdir = tempdir( CLEANUP => 1, DIR => $options{tmpdir} || '/tmp' ); | |
my @modules_to_build = ( { name => $module, version => $options{version} } ); | |
delete $options{version}; | |
while ( my $mod = shift @modules_to_build ) { | |
build_module( $mod->{name}, $mod->{version} ); | |
} | |
sub build_module { | |
my ( $module, $version ) = @_; | |
my $tarball = get_file_from_cpan_web($module, $version); | |
return unless $tarball; | |
my $resolved = resolve_dependencies($tarball); | |
if ( $resolved ) { | |
my $opts = join ' ', map { | |
do { | |
if ( $options{$_} == 1 ) { | |
"--$_"; | |
} | |
else { | |
"--$_=$options{$_}" | |
} | |
} | |
} keys %options; | |
print_log( info => "cpanflute2 $opts $tmpdir/$tarball" ); | |
system "cpanflute2 $opts $tmpdir/$tarball"; | |
unless ( $? ) { | |
my $package = get_package_name($module); | |
$package = "perl-$package"; | |
my @rpms = glob("$package*.rpm"); | |
for my $rpm ( @rpms ) { | |
next if $rpm =~ /src\.rpm/; | |
`sudo rpm -Uvh $rpm`; | |
} | |
} | |
} | |
else { | |
push @modules_to_build,{ name => $module, version => $version }; | |
} | |
} | |
sub get_file_from_cpan_web { | |
my ( $module, $version ) = @_; | |
my $tarball_url = get_tarball_url($module, $version); | |
my ($loc, $file) = $tarball_url =~ m|(.*)/(.*)|; | |
print_log( info => "Getting $file ..."); | |
mirror($tarball_url, "$tmpdir/$file"); | |
return $file; | |
} | |
sub get_tarball_url { | |
my ( $module, $version ) = @_; | |
my $base = "http://search.cpan.org"; | |
my $url = "$base/dist/$module"; | |
$url =~ s/::/-/g; | |
$url .= "-$version" if $version; | |
local $_ = LWP::Simple::get($url) || return; | |
m% \<a[^<>]* # Begin Anchor tag | |
href\s*=\s* # href parameter | |
(['"]?) # Maybe quote | |
([^<>\s"']*) # Extract link as $2 | |
\1 # Maybe quote | |
[^<>]*\> # End Anchor tag | |
\s*Download # of the "Download" link | |
%ix; # case insensitive HTML | |
my $tarball_url = "$base$2" if $2; | |
unless ( $2 ) { | |
my $package = get_package_name($module); | |
$tarball_url = get_tarball_url($package); | |
} | |
die "$module not found on CPAN web site!" | |
unless $tarball_url; | |
return $tarball_url; | |
} | |
sub resolve_dependencies { | |
my $tarball = shift; | |
my @files = Archive::Tar->list_archive("$tmpdir/$tarball"); | |
my $use_module_build = 1 if grep { /Build\.PL$/ } @files; | |
my $resolved = 1; | |
my %prefixes; | |
foreach (@files) { | |
my @path_components = split m[/], $_; | |
$prefixes{$path_components[0]}++; | |
if ($path_components[-1] eq 'META.yml') { | |
my $tar = new Archive::Tar; | |
$tar->read("$tmpdir/$tarball", 1); | |
my $contents = $tar->get_content($_); | |
my $yaml = YAML::Load($contents); | |
while (my ($mod, $ver) = each %{$yaml->{build_requires}}) { | |
next if $mod eq 'perl'; | |
unless ( install_package($mod, $ver) ) { | |
push @modules_to_build, { name => $mod, version => 0 }; | |
$resolved = 0; | |
} | |
} | |
while (my ($mod, $ver) = each %{$yaml->{requires}}) { | |
next if $mod eq 'perl'; | |
unless ( install_package($mod, $ver) ) { | |
push @modules_to_build, { name => $mod, version => 0 }; | |
$resolved = 0; | |
} | |
} | |
while (my ($mod, $ver) = each %{$yaml->{recommends}}) { | |
next if $mod eq 'perl'; | |
unless ( install_package($mod, $ver) ) { | |
push @modules_to_build, { name => $mod, version => 0 }; | |
$resolved = 0; | |
} | |
} | |
} | |
} | |
return $resolved; | |
} | |
sub install_package { | |
my ( $module, $version ) = @_; | |
$module = $use_module_mapping{$module} if $use_module_mapping{$module}; | |
# モジュールが存在するかチェック | |
if ( grep { $module eq $_ } @doc_modules ) { | |
`perldoc -l $module`; | |
return 1 unless $?; | |
} | |
else { | |
print_log( info => "Checking $module $version'" ); | |
my $check = check_module_and_version( $module, $version ); | |
# 存在するなら return | |
return 1 if $check; | |
} | |
print_log( info => "Required module $module $version not found" ); | |
my $package = get_package_name($module); | |
$package = "perl-$package"; | |
# パッケージが存在するかチェック | |
`rpm -q $package`; | |
# 存在する場合は yum update してみる | |
unless ( $? ) { | |
print_log( info => "Trying to update a required package $package ..."); | |
run3("sudo yum update -y $package", \my $in, \my $out, \my $err); | |
print_log( 'debug' => $out ); | |
if ( $out =~ /no packages marked for update/i ) { | |
# update できなかったら 0 で treturn | |
print_log( error => "Failed to update $package"); | |
return 0; | |
} | |
else { | |
# もう一度モジュール存在チェック | |
print_log( info => "Succeeded to update $package"); | |
my $check = check_module_and_version( $module, $version ); | |
return 1 if $check; | |
} | |
} | |
else { | |
# 存在しなければパッケージインストールしてみる | |
print_log( info => "Trying to install a required package $package ..."); | |
run3("sudo yum install -y $package", \my $in, \my $out, \my $err); | |
print_log( 'debug' => $out ); | |
if ( $out =~ /Nothing to do/ ) { | |
print_log( error => "Failed to install $package"); | |
return 0; | |
} | |
else { | |
print_log( info => "Succeeded to install $package"); | |
return 1; | |
} | |
} | |
} | |
sub get_package_name { | |
my $module = shift; | |
my $content = get("http://search.cpan.org/search?query=$module") || return; | |
my ( $package ) = ( $content =~ m!href="/~[^/]+/([^/]+)/"! ); | |
$package =~ s/-[^-]+$//; | |
return $package; | |
} | |
# ログ表示用のルーチン | |
sub print_log { | |
my( $level, $msg ) = @_; | |
return unless should_log($level); | |
chomp($msg); | |
warn "[$level] $msg\n"; | |
} | |
sub should_log { | |
my $level = shift; | |
my %levels = ( | |
debug => 0, | |
warn => 1, | |
info => 2, | |
error => 3, | |
); | |
$levels{$level} >= $levels{$log_level}; | |
} | |
sub check_module_and_version { | |
# code from ExtUtils::MakeMaker | |
my ( $module, $version ) = @_; | |
my $file = "${module}.pm"; | |
$file =~ s{::}{/}g; | |
eval { require $file }; | |
my $pr_version = $module->VERSION || 0; | |
# convert X.Y_Z alpha version #s to X.YZ for easier comparisons | |
$pr_version =~ s/(\d+)\.(\d+)_(\d+)/$1.$2$3/; | |
if ( $@ or $pr_version < $version ) { | |
return 0; | |
} | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment