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.
This commit is contained in:
Timo Teräs 2011-06-02 11:55:00 +03:00
parent 7f122b77e8
commit f670c88e53
3 changed files with 337 additions and 197 deletions

View File

@ -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

336
apkbuild-cpan.in Executable file
View File

@ -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;
}
}

View File

@ -1,196 +0,0 @@
#!/bin/sh
# script to generate a new APKBUILD
# Copyright (c) 2009 Natanael Copa <natanael.copa@gmail.com>
#
# 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