diff options
author | Timo Teräs <timo.teras@iki.fi> | 2011-06-02 11:55:00 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2011-06-02 11:55:00 +0300 |
commit | f670c88e530965eeb0b7c3bae5640cab69344883 (patch) | |
tree | 699bdb7d95e509debe604414ed28f53cf419bdaa /apkbuild-cpan.in | |
parent | 7f122b77e87fd69ec26afba2b022f2a1d4b33e7c (diff) | |
download | abuild-f670c88e530965eeb0b7c3bae5640cab69344883.tar.gz abuild-f670c88e530965eeb0b7c3bae5640cab69344883.tar.bz2 abuild-f670c88e530965eeb0b7c3bae5640cab69344883.tar.xz abuild-f670c88e530965eeb0b7c3bae5640cab69344883.zip |
apkbuild-cpan: new tool superceding newapkbuild-cpan tool
Based on Aerdan's original work, this is a perl utility that
interacts with CPAN which can create and update APKBUILDs with
proper metadata info.
Diffstat (limited to 'apkbuild-cpan.in')
-rwxr-xr-x | apkbuild-cpan.in | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/apkbuild-cpan.in b/apkbuild-cpan.in new file mode 100755 index 0000000..75e7dd0 --- /dev/null +++ b/apkbuild-cpan.in @@ -0,0 +1,336 @@ +#!/usr/bin/perl +# apk add perl-libwww perl-json + +use strict; +use warnings; +use feature qw(:5.10); +use LWP::UserAgent; +use LWP::ConnCache; +use CPAN::Meta; +use Module::CoreList; +use JSON; + +my $license_mappings = { + "perl_5" => "GPL PerlArtistic", + "artistic_2" => "Artistic-2", +}; + +my $package_mappings = { + "LWP" => "perl-libwww", + "TermReadKey" => "perl-term-readkey", +}; +our $packager = ""; +my $template = <<'EOF'; +# Automatically generated by apkbuild-cpan, template 1 +# Contributor: [% packager %] +# Maintainer: [% packager %] +pkgname=[% pkgname %] +_pkgreal=[% pkgreal %] +pkgver=[% pkgver %] +pkgrel=0 +pkgdesc="Perl module for [% pkgreal %]" +url="http://search.cpan.org/dist/[% pkgreal %]/" +arch="noarch" +license="GPL PerlArtistic" +cpandepends="" +cpanmakedepends="" +depends="$cpandepends" +makedepends="perl-dev $cpanmakedepends" +subpackages="$pkgname-doc" +source="[% source %]" + +_builddir="$srcdir/$_pkgreal-$pkgver" + +prepare() { + cd "$_builddir" + if [ -e Build.PL ]; then + perl Build.PL installdirs=vendor || return 1 + else + PERL_MM_USE_DEFAULT=1 perl Makefile.PL INSTALLDIRS=vendor || return 1 + fi +} + +build() { + : +} + +package() { + : +} + +EOF + +our $ua = LWP::UserAgent->new(); +our $json = JSON->new; +$ua->env_proxy; +$ua->conn_cache(LWP::ConnCache->new()); + +sub read_file +{ + my ($filename) = @_; + local $/; + open my $fh, "<", $filename or die "could not open $filename: $!"; + return <$fh>; +} + +sub read_assignments_from_file { + my ($filename) = @_; + my $text = read_file($filename); + my %sline = $text =~ /^(\w+)\s*=\s*([^\"\n]*)$/mg; + my %mline = $text =~ /^(\w+)\s*=\s*\"([^\"]*)\"$/mg; + my %hash = ( %sline, %mline ); + return \%hash; +} + +sub map_cpan_to_apk { + my ($cpan_distrib) = @_; + return $package_mappings->{$cpan_distrib} if exists $package_mappings->{$cpan_distrib}; + # most packages are named according to the + # distribution name + return 'perl-' . lc $cpan_distrib; +} + +sub read_apkbuild { + return read_assignments_from_file("APKBUILD"); +} + +sub write_apkbuild { + my ($distdata) = @_; + + my $cpanid = $distdata->{releases}[0]->{cpanid}; + $cpanid = substr($cpanid, 0, 1) . "/" . substr($cpanid, 0, 2) . "/$cpanid"; + my %repl = ( + packager => $packager, + pkgname => map_cpan_to_apk($distdata->{name}), + pkgreal => $distdata->{name}, + pkgver => $distdata->{releases}[0]->{version}, + source => "http://search.cpan.org/CPAN/authors/id/$cpanid/\$_pkgreal-\$pkgver.tar.gz", + ); + $template =~ s/\[% (.*?) %\]/$repl{$1}/g; + + open my $fh, '>', "APKBUILD" or die; + print $fh $template; + close $fh; + + say "Wrote $repl{pkgname}/APKBUILD"; +} + +sub parse_deps { + my ($reqs) = @_; + my $distfiles = {}; + my $response; + my $deps = ""; + + for my $module ($reqs->required_modules) { + if (my $perlver = Module::CoreList->first_release($module)) { + say "$module is part of core perl since $perlver."; + next; + } + next if $module eq 'perl'; + + # map module name to package name + $response = $ua->get("http://search.cpan.org/api/module/$module"); + $response->is_success or die $response->status_line; + my $moddata = $json->decode($response->decoded_content); + $moddata->{error} and die "Error trying to locate $module: $moddata->{error}\n"; + $distfiles->{$moddata->{distvname}} = $moddata; + } + + # map package names to alpine packages + foreach ( keys $distfiles ) { + $response = $ua->get("http://search.cpan.org/api/dist/$_"); + $response->is_success or die $response->status_line; + my $distdata = $json->decode($response->decoded_content); + $distdata->{error} and die "Error trying to locate $_: $distdata->{error}\n"; + + my $pkgname = map_cpan_to_apk($distdata->{name}); + $deps .= "$pkgname "; + } + $deps =~ s/\s+$//; + return $deps; + +} + +sub prepare_tree { + system("abuild checksum unpack prepare") == 0 or + die "abuild checksum failed"; +} + +sub update_functions { + my $apkbuild = read_apkbuild; + my $metaprefix = "src/" . $apkbuild->{'_pkgreal'} . "-" . $apkbuild->{'pkgver'} . "/"; + my $prepare_func; + my $build_func; + my $package_func; + + my $text = read_file "APKBUILD"; + if (-e "$metaprefix/Build.PL" ) { + $prepare_func = <<'EOF'; +prepare() { + cd "$_builddir" + perl Build.PL installdirs=vendor || return 1 +} +EOF + $build_func = <<'EOF'; +build() { + cd "$_builddir" + ./Build && ./Build test +} +EOF + $package_func = <<'EOF'; +package() { + cd "$_builddir" + ./Build install destdir="$pkgdir" || return 1 + find "$pkgdir" \( -name perllocal.pod -o -name .packlist \) -delete +} +EOF + } else { + $prepare_func = <<'EOF'; +prepare() { + cd "$_builddir" + PERL_MM_USE_DEFAULT=1 perl Makefile.PL INSTALLDIRS=vendor +} +EOF + $build_func = <<'EOF'; +build() { + cd "$_builddir" + make && make test +} +EOF + $package_func = <<'EOF'; +package() { + cd "$_builddir" + make DESTDIR="$pkgdir" install || return 1 + find "$pkgdir" \( -name perllocal.pod -o -name .packlist \) -delete +} +EOF + } + + $text =~ s/^prepare\(\) \{.*?^\}\n/$prepare_func/smg or + die "Can't replace prepare function APKBUILD"; + $text =~ s/^build\(\) \{.*?^\}\n/$build_func/smg or + die "Can't replace build function APKBUILD"; + $text =~ s/^package\(\) \{.*?^\}\n/$package_func/smg or + die "Can't replace package function APKBUILD"; + + open my $fh, '>', "APKBUILD" or die; + print $fh $text; + close $fh; +} + +sub do_depends { + my $apkbuild = read_apkbuild; + my $metaprefix = "src/" . $apkbuild->{'_pkgreal'} . "-" . $apkbuild->{'pkgver'} . "/"; + my $meta; + + foreach my $metafile ("MYMETA.json", "META.json", "MYMETA.yml", "META.yml") { + if (-e "$metaprefix$metafile") { + say "Using meta information from $metafile"; + $meta = CPAN::Meta->load_file("$metaprefix$metafile"); + last; + } + } + die "No dependency meta file found" unless $meta; + + my $abstract = $meta->abstract; + say "Abstract: $abstract"; + + my $license = join " ", map {$license_mappings->{$_} or $_} $meta->license; + say "License: $license"; + + my $deps = parse_deps $meta->effective_prereqs->requirements_for('runtime', 'requires'); + say "CPAN deps: $deps"; + + my $makedeps = parse_deps $meta->effective_prereqs->requirements_for('build', 'requires'); + say "CPAN build deps: $makedeps"; + + my $text = read_file "APKBUILD"; + if ($abstract) { + $text =~ s/^pkgdesc=\"([^\"]*)\"$/pkgdesc=\"$abstract\"/mg or + die "Can't find cpandepends line in APKBUILD"; + } + $text =~ s/^license=\"([^\"]*)\"$/license=\"$license\"/mg or + die "Can't find cpandepends line in APKBUILD"; + $text =~ s/^cpandepends=\"([^\"]*)\"$/cpandepends=\"$deps\"/mg or + die "Can't find cpandepends line in APKBUILD"; + $text =~ s/^cpanmakedepends=\"([^\"]*)\"$/cpanmakedepends=\"$makedeps\"/mg or + die "Can't find cpanmakedepends line in APKBUILD"; + + open my $fh, '>', "APKBUILD" or die; + print $fh $text; + close $fh; +} + +my $abuild_conf = read_assignments_from_file("/etc/abuild.conf"); +$packager = $abuild_conf->{PACKAGER} if $abuild_conf->{PACKAGER}; + +given ( $ARGV[0] ) { + when ("create") { + my $module = $ARGV[1]; + my $response; + $module or die "Module name is a mandatory argument"; + + $response = $ua->get("http://search.cpan.org/api/module/$module"); + $response->is_success or die $response->status_line; + my $moddata = $json->decode($response->decoded_content); + $moddata->{error} and die "Error trying to locate $module: $moddata->{error}\n"; + + $response = $ua->get("http://search.cpan.org/api/dist/$moddata->{distvname}"); + $response->is_success or die $response->status_line; + my $distdata = $json->decode($response->decoded_content); + $distdata->{error} and die "Error trying to locate $module: $distdata->{error}\n"; + + my $apkname = map_cpan_to_apk $distdata->{name}; + mkdir $apkname; + chdir $apkname; + write_apkbuild($distdata); + prepare_tree; + update_functions; + do_depends; + } + when ("recreate") { + my $apkbuild = read_apkbuild; + my $response = $ua->get("http://search.cpan.org/api/dist/$apkbuild->{_pkgreal}"); + $response->is_success or die $response->status_line; + my $distdata = $json->decode($response->decoded_content); + $distdata->{error} and die "Error trying to locate $apkbuild->{_pkgreal}: $distdata->{error}\n"; + + write_apkbuild($distdata); + prepare_tree; + update_functions; + do_depends; + } + when ("upgrade") { + my $apkbuild = read_apkbuild; + my $response = $ua->get("http://search.cpan.org/api/dist/$apkbuild->{_pkgreal}"); + $response->is_success or die $response->status_line; + my $distdata = $json->decode($response->decoded_content); + $distdata->{error} and die "Error trying to locate $apkbuild->{_pkgreal}: $distdata->{error}\n"; + + my $pkgver = $distdata->{releases}[0]->{version}; + if ($pkgver != $apkbuild->{pkgver}) { + say "Upgrading CPAN module from $apkbuild->{pkgver} to $pkgver"; + + my $text = read_file "APKBUILD"; + $text =~ s/^pkgver=(.*)$/pkgver=$pkgver/mg or + die "Can't find pkgver line in APKBUILD"; + $text =~ s/^pkgrel=(.*)$/pkgrel=0/mg; + open my $fh, '>', "APKBUILD" or die; + say $fh $text; + close $fh; + + prepare_tree; + do_depends; + } else { + say "Up-to-data with CPAN"; + } + } + when ("update") { + prepare_tree; + do_depends; + } + default { + say "Usage: apkbuild-cpan [create <Module::Name> | recreate | upgrade | update]"; + exit; + } +} |