From f670c88e530965eeb0b7c3bae5640cab69344883 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Thu, 2 Jun 2011 11:55:00 +0300 Subject: 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. --- Makefile | 2 +- apkbuild-cpan.in | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++ newapkbuild-cpan.in | 196 ------------------------------ 3 files changed, 337 insertions(+), 197 deletions(-) create mode 100755 apkbuild-cpan.in delete mode 100755 newapkbuild-cpan.in diff --git a/Makefile b/Makefile index d63f9e9..d619773 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ LUA_SHAREDIR ?= $(prefix)/share/lua/$(LUA_VERSION)/ SCRIPTS := abuild devbuild buildrepo abuild-keygen \ abuild-sign newapkbuild abump apkgrel ap buildlab \ - newapkbuild-cpan + apkbuild-cpan USR_BIN_FILES := $(SCRIPTS) abuild-tar SAMPLES := sample.APKBUILD sample.initd sample.confd \ sample.pre-install sample.post-install 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 | recreate | upgrade | update]"; + exit; + } +} diff --git a/newapkbuild-cpan.in b/newapkbuild-cpan.in deleted file mode 100755 index 9ae726b..0000000 --- a/newapkbuild-cpan.in +++ /dev/null @@ -1,196 +0,0 @@ -#!/bin/sh - -# script to generate a new APKBUILD -# Copyright (c) 2009 Natanael Copa -# -# Distributed under GPL-2 -# -# Depends on: busybox utilities, fakeroot, -# - -version=@VERSION@ -sysconfdir=@sysconfdir@ -datadir=@datadir@ - -prog=${0##*/} - -# source $PACKAGER -for i in $sysconfdir/abuild.conf $HOME/.abuild/abuild.conf; do - if [ -f "$i" ]; then - . $i - fi -done - -error() { - echo "$@" >&2 -} - -is_url() { - case "$1" in - http://*|ftp://*) return 0;; - esac - return 1 -} - -get_cpan_source() { - local mod="$1" - wget -q -O - http://search.cpan.org/dist/$mod/ \ - | grep "href.*$mod-[0-9].*Download" \ - | sed "s|.*href=\"\(.*\)\".*|http://search.cpan.org\1|" -} - -# create new aport from templates -newaport() { - local newname= pv= source= pn= mod= - - if is_url "$1"; then - source="$1" - newname="${1##*/}" - mod=$(echo $pn | sed 's/-/::/g') - else - if echo $1 | grep -q '::'; then - mod=$1 - pn=$(echo $mod | sed 's/::/-/g') - else - pn=$1 - mod=$(echo $pn | sed 's/-/::/g') - fi - source=$(get_cpan_source $pn) - newname="${source##*/}" - fi - if [ -z "$source" ]; then - error "source not found" - exit 1 - fi - pn=${newname%-[0-9]*} - pv=${newname#$pn-} - - if [ "$pn" != "$newname" ]; then - pv=${newname#$pn-} - pv=${pv%.t*} #strip .tar.gz .tgz .tar.bz2 etc - fi - pkgname=perl-$(echo $pn | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz') - - if [ -e "$pkgname"/APKBUILD ] && [ -z "$force" ]; then - error "$pkgname/APKBUILD already exist" - return 1 - fi - mkdir -p "$pkgname" - cd "$pkgname" - - # replace pkgver in $source - if [ -n "$source" ]; then - source=$(echo "$source" | sed "s/$pv/\$pkgver/g") - fi - - if [ -z "$url" ]; then - url="http://search.cpan.org/dist/$pn/" - fi - - if [ -z "$license" ]; then - license="GPLv2 or Artistic" - fi - - if [ -z "$pkgdesc" ]; then - pkgdesc="$mod perl module" - fi - - # generate header with standard variables - cat >APKBUILD<<__EOF__ -# Contributor:${PACKAGER:+" "}${PACKAGER} -# Maintainer:${MAINTAINER:+" "}${MAINTAINER} -pkgname=$pkgname -pkgver=$pv -pkgrel=0 -pkgdesc="$pkgdesc" -url="$url" -arch="noarch" -license="$license" -depends="perl" -makedepends="perl-dev" -install="$install" -subpackages="\$pkgname-doc" -source="$source" - -__EOF__ - - abuild -f fetch unpack - # figure out the _builddir - for i in src/*; do - if [ -d "$i" ]; then - sdir=$i - _builddir=$(echo ${i#*/} | sed "s/$pv/\$pkgver/g") - _builddir="\"\$srcdir\"/$_builddir" - fi - done - echo "_builddir=$_builddir" >> APKBUILD - - # create the prepare() template - cat >>APKBUILD<<__EOF__ -prepare() { - local i - cd "\$_builddir" - for i in \$source; do - case \$i in - *.patch) msg \$i; patch -p1 -i "\$srcdir"/\$i || return 1;; - esac - done -} - -__EOF__ - - # create build() - cat >>APKBUILD<<__EOF__ -build() { - cd "\$_builddir" - PERL_MM_USE_DEFAULT=1 perl Makefile.PL INSTALLDIRS=vendor || return 1 - make && make test || return 1 -} - -package() { - cd "\$_builddir" - make DESTDIR="\$pkgdir" install || return 1 - find "\$pkgdir" \\( -name perllocal.pod -o -name .packlist \\) -delete -} - -__EOF__ - abuild -r checksum all -} - -usage() { - echo "$prog $version" - echo "usage: $prog [-cfh] [-d DESC] [-l LICENSE] [-u URL] PKGNAME[-PKGVER]" - echo "Options:" - echo " -a Create autotools (use ./configure ...)" - echo " -c Copy a sample init.d, conf.d and install script to new directory" - echo " -d Set package description (pkgdesc) to DESC" - echo " -f Force even if directory already exist" - echo " -h Show this help" - echo " -l Set package license to LICENSE" - echo " -p Create perl package (Assume Makefile.PL is there)" - echo " -u Set package URL" - echo " -s Use sourceforge source url" - echo "" - exit 0 -} - -while getopts "acd:fhl:pu:s" opt; do - case $opt in - 'a') buildtype="autotools";; - 'c') cpinitd=1;; - 'd') pkgdesc="$OPTARG";; - 'f') force=1;; - 'h') usage;; - 'l') license="$OPTARG";; - 'p') buildtype="perl";; - 'u') url="$OPTARG";; - 's') sourceforge=1;; - esac -done -shift $(( $OPTIND - 1 )) - -while [ $# -gt 0 ]; do - (newaport $1) || exit 1 - shift -done - -- cgit v1.2.3-70-g09d2