2011-11-03 12:57:19 +00:00
|
|
|
#!/usr/bin/perl
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use autodie qw(:all);
|
|
|
|
use feature qw(:5.14);
|
|
|
|
use LWP::UserAgent;
|
|
|
|
use LWP::ConnCache;
|
|
|
|
use JSON;
|
2023-12-12 13:58:42 +00:00
|
|
|
use URI;
|
2023-12-13 02:15:57 +00:00
|
|
|
use Text::Wrap qw(wrap $columns);
|
2011-11-03 12:57:19 +00:00
|
|
|
|
|
|
|
our $packager = '';
|
|
|
|
my %pkgmap = ();
|
|
|
|
my %licenses = ();
|
|
|
|
|
|
|
|
my $template = <<'EOF';
|
2023-12-12 14:07:37 +00:00
|
|
|
# Automatically generated by apkbuild-pypi, template 4
|
2019-08-04 01:28:00 +00:00
|
|
|
[% authors %]
|
2011-11-03 12:57:19 +00:00
|
|
|
pkgname=[% pkgname %]
|
2021-01-23 01:17:41 +00:00
|
|
|
#_pkgreal is used by apkbuild-pypi to find modules at PyPI
|
2016-06-12 14:13:14 +00:00
|
|
|
_pkgreal=[% pkgreal %]
|
2011-11-03 12:57:19 +00:00
|
|
|
pkgver=[% pkgver %]
|
2021-01-23 01:17:41 +00:00
|
|
|
pkgrel=[% pkgrel %]
|
2019-08-04 01:28:00 +00:00
|
|
|
pkgdesc="[% pkgdesc %]"
|
2023-12-16 04:18:33 +00:00
|
|
|
url="[% url %]"
|
2011-11-03 12:57:19 +00:00
|
|
|
arch="noarch"
|
2019-08-04 01:28:00 +00:00
|
|
|
license="[% license %]"
|
2023-12-13 02:04:02 +00:00
|
|
|
depends=""
|
2023-12-12 14:07:37 +00:00
|
|
|
makedepends="py3-gpep517 py3-setuptools py3-wheel"
|
|
|
|
checkdepends="py3-pytest"
|
2023-12-12 15:42:24 +00:00
|
|
|
subpackages="$pkgname-pyc"
|
2011-11-03 12:57:19 +00:00
|
|
|
source="[% source %]"
|
2016-06-12 14:11:51 +00:00
|
|
|
builddir="$srcdir/$_pkgreal-$pkgver"
|
2023-12-16 04:10:09 +00:00
|
|
|
[% compatibility %]
|
2011-11-03 12:57:19 +00:00
|
|
|
build() {
|
2023-12-12 14:07:37 +00:00
|
|
|
gpep517 build-wheel \
|
|
|
|
--wheel-dir .dist \
|
|
|
|
--output-fd 3 3>&1 >&2
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
|
|
|
|
2021-01-23 01:17:41 +00:00
|
|
|
check() {
|
2023-12-12 14:07:37 +00:00
|
|
|
python3 -m venv --clear --without-pip --system-site-packages .testenv
|
|
|
|
.testenv/bin/python3 -m installer .dist/*.whl
|
|
|
|
.testenv/bin/python3 -m pytest
|
2021-01-23 01:17:41 +00:00
|
|
|
}
|
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
package() {
|
2023-12-12 14:07:37 +00:00
|
|
|
python3 -m installer -d "$pkgdir" \
|
|
|
|
.dist/*.whl
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
2019-08-04 01:28:00 +00:00
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
EOF
|
|
|
|
|
|
|
|
my $ua = LWP::UserAgent->new();
|
|
|
|
my $json = JSON->new;
|
|
|
|
$ua->env_proxy;
|
|
|
|
$ua->conn_cache(LWP::ConnCache->new);
|
|
|
|
|
|
|
|
sub read_file {
|
|
|
|
my ($filename) = @_;
|
|
|
|
open my $fh, '<:utf8', $filename;
|
|
|
|
local $/;
|
|
|
|
my $text = <$fh>;
|
|
|
|
return $text;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub read_assignments_from_file {
|
|
|
|
my ($filename) = @_;
|
2019-08-04 01:28:00 +00:00
|
|
|
return () if ( ! -e $filename );
|
2011-11-03 12:57:19 +00:00
|
|
|
my $text = read_file($filename);
|
|
|
|
my %sline = $text =~ /^(\w+)\s*=\s*([^\"\n]*)$/mg;
|
2021-01-23 01:17:41 +00:00
|
|
|
my %mline = $text =~ /^(\w+)\s*=\s*\"([^\"]*)\".*$/mg;
|
2019-08-04 01:28:00 +00:00
|
|
|
my %hash = ( %sline, %mline );
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2019-08-04 01:28:00 +00:00
|
|
|
my $authors = join("\n", $text =~ /^# Contributor: .*$/mg, $text =~ /^# Maintainer: .*$/mg);
|
|
|
|
$hash{'authors'} = $authors if length($authors) > 1;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2021-01-23 01:17:41 +00:00
|
|
|
my $provides = $text =~ m/provides=\"(.*)\"".*/mg;
|
|
|
|
$hash{'provides'} = $1 if length($provides) >= 1;
|
|
|
|
|
|
|
|
my $requires = $text =~ m/^requires=\"(.*)\"".*$/mg;
|
|
|
|
$hash{'requires'} = $1 if length($requires) >= 1;
|
|
|
|
|
2019-08-04 01:28:00 +00:00
|
|
|
return \%hash;
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub map_pypi_to_apk {
|
|
|
|
my ($pypi) = @_;
|
|
|
|
return $pkgmap{$pypi} unless !exists($pkgmap{$pypi});
|
2019-08-04 01:28:00 +00:00
|
|
|
return 'py3-'.lc($pypi);
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub map_license {
|
|
|
|
my ($license) = @_;
|
|
|
|
|
|
|
|
$license =~ s/ or / /g;
|
|
|
|
|
|
|
|
return $license;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub get_source {
|
|
|
|
my ($distdata) = @_;
|
2023-12-12 13:58:42 +00:00
|
|
|
my $pkgname = $distdata->{info}{name};
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-12-12 13:58:42 +00:00
|
|
|
my $source;
|
2011-11-03 12:57:19 +00:00
|
|
|
for my $url (@{$distdata->{urls}}) {
|
2023-12-12 13:58:42 +00:00
|
|
|
if ($url->{python_version} eq 'source') {
|
|
|
|
$source = URI->new($url->{url});
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
die "Unable to locate sources for $pkgname.\n" unless $source;
|
|
|
|
|
|
|
|
my $filename = ($source->path_segments)[-1];
|
|
|
|
my $pretty_path = substr($pkgname, 0, 1) . "/$pkgname";
|
|
|
|
my $pretty_url = $source->clone;
|
|
|
|
$pretty_url->path("/packages/source/$pretty_path/$filename");
|
|
|
|
|
|
|
|
my $response = $ua->head($pretty_url);
|
|
|
|
if ($response->is_success) {
|
|
|
|
return $pretty_url->as_string;
|
|
|
|
} else {
|
|
|
|
return $source->as_string;
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub read_apkbuild {
|
|
|
|
return read_assignments_from_file('APKBUILD');
|
|
|
|
}
|
|
|
|
|
|
|
|
sub write_apkbuild {
|
2021-01-23 01:17:41 +00:00
|
|
|
my ($distdata, $apkbuild) = @_;
|
|
|
|
|
|
|
|
my $replaces = undef;
|
|
|
|
my $provides = undef;
|
|
|
|
my $authors = undef;
|
2023-12-16 04:18:33 +00:00
|
|
|
my $license = undef;
|
|
|
|
my $url = undef;
|
|
|
|
my $pkgname = undef;
|
|
|
|
my $pkgdesc = undef;
|
2021-01-23 01:17:41 +00:00
|
|
|
my $pkgrel = 0;
|
|
|
|
|
|
|
|
if (defined $apkbuild) {
|
|
|
|
$authors = $apkbuild->{authors};
|
|
|
|
$provides = $apkbuild->{provides};
|
|
|
|
$replaces = $apkbuild->{replaces};
|
2023-12-16 04:18:33 +00:00
|
|
|
$license = $apkbuild->{license};
|
|
|
|
$url = $apkbuild->{url};
|
|
|
|
$pkgname = $apkbuild->{pkgname};
|
|
|
|
$pkgdesc = $apkbuild->{pkgdesc};
|
2021-01-23 01:17:41 +00:00
|
|
|
$pkgrel = $apkbuild->{pkgrel};
|
|
|
|
|
|
|
|
if ($apkbuild->{pkgver} eq $distdata->{info}{version}) {
|
|
|
|
$pkgrel++;
|
|
|
|
}
|
|
|
|
}
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-12-16 04:18:33 +00:00
|
|
|
my $pkgreal = $distdata->{info}{name};
|
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
my %repl = (
|
2019-08-04 01:28:00 +00:00
|
|
|
authors => ($authors or "# Contributor: $packager\n# Maintainer: $packager"),
|
2023-12-16 04:18:33 +00:00
|
|
|
pkgname => ($pkgname or map_pypi_to_apk($pkgreal)),
|
|
|
|
pkgreal => $pkgreal,
|
2011-11-03 12:57:19 +00:00
|
|
|
pkgver => $distdata->{info}{version},
|
2021-01-23 01:17:41 +00:00
|
|
|
pkgrel => $pkgrel,
|
2011-11-03 12:57:19 +00:00
|
|
|
source => get_source($distdata),
|
2023-12-16 04:18:33 +00:00
|
|
|
license => ($license or map_license($distdata->{info}{license})),
|
|
|
|
url => ($url or "https://pypi.org/project/${pkgreal}/"),
|
|
|
|
pkgdesc => ($pkgdesc or $distdata->{info}{summary}),
|
2011-11-03 12:57:19 +00:00
|
|
|
);
|
2023-12-16 04:10:09 +00:00
|
|
|
|
|
|
|
$repl{compatibility} .= "\nreplaces=\"$replaces\"" if $replaces;
|
|
|
|
$repl{compatibility} .= "\nprovides=\"$provides\"" if $provides;
|
|
|
|
$repl{compatibility} .= "\n" if $replaces or $provides;
|
|
|
|
|
2023-12-13 01:26:23 +00:00
|
|
|
$repl{source} =~ s/-$repl{pkgver}/-\$pkgver/g;
|
2011-11-03 12:57:19 +00:00
|
|
|
$template =~ s/\[% (.*?) %\]/$repl{$1}/g;
|
|
|
|
|
|
|
|
open my $fh, '>:utf8', 'APKBUILD';
|
|
|
|
print {$fh} $template;
|
|
|
|
close $fh;
|
|
|
|
|
|
|
|
say "Wrote $repl{pkgname}/APKBUILD";
|
|
|
|
|
|
|
|
return \%repl;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub prepare_tree {
|
|
|
|
system('abuild checksum unpack prepare');
|
|
|
|
}
|
|
|
|
|
2021-01-23 01:17:41 +00:00
|
|
|
sub find_package_name {
|
|
|
|
my ($apkbuild) = @_;
|
|
|
|
|
|
|
|
my $pkgreal = '';
|
|
|
|
|
|
|
|
if (exists $apkbuild->{_realname}) {
|
|
|
|
$pkgreal = $apkbuild->{_realname};
|
|
|
|
} elsif (exists $apkbuild->{_pkgreal}) {
|
|
|
|
$pkgreal = $apkbuild->{_pkgreal};
|
|
|
|
} elsif (exists $apkbuild->{_pkgname}) {
|
|
|
|
$pkgreal = $apkbuild->{_pkgname};
|
|
|
|
} elsif (exists $apkbuild->{_name}) {
|
|
|
|
$pkgreal = $apkbuild->{_name};
|
|
|
|
} elsif (exists $apkbuild->{_realpkgname}) {
|
|
|
|
$pkgreal = $apkbuild->{_realpkgname};
|
|
|
|
} elsif (exists $apkbuild->{_pkg_real}) {
|
|
|
|
$pkgreal = $apkbuild->{_pkg_real};
|
|
|
|
} elsif (exists $apkbuild->{source}) {
|
|
|
|
$pkgreal = $apkbuild->{source};
|
|
|
|
$pkgreal =~ m/(\w+)-/;
|
|
|
|
$pkgreal = $1;
|
|
|
|
} else {
|
|
|
|
print "No pkg real found\n";
|
|
|
|
die;
|
|
|
|
}
|
|
|
|
return $pkgreal;
|
|
|
|
}
|
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
sub get_data {
|
|
|
|
my ($package) = @_;
|
2023-12-13 02:40:46 +00:00
|
|
|
my $response = $ua->get("https://pypi.org/pypi/$package/json");
|
2011-11-03 12:57:19 +00:00
|
|
|
$response->is_success or die $response->status_line;
|
|
|
|
my $distdata = $json->decode($response->decoded_content);
|
|
|
|
|
|
|
|
return $distdata;
|
|
|
|
}
|
|
|
|
|
2023-12-13 02:15:57 +00:00
|
|
|
sub format_depends {
|
|
|
|
my $deps = shift;
|
|
|
|
|
|
|
|
$columns = 102;
|
|
|
|
|
|
|
|
$deps =~ s/ {2,}/ /g;
|
|
|
|
$deps =~ s/^\s//g;
|
|
|
|
$deps =~ s/\s$//g;
|
|
|
|
|
|
|
|
if ( length($deps) >= $columns ) {
|
|
|
|
$deps = wrap( "\t", "\t", $deps );
|
|
|
|
}
|
|
|
|
$deps =~ s/\s$//g;
|
|
|
|
|
|
|
|
if ( length($deps) >= $columns ) {
|
|
|
|
$deps = "\n" . $deps . "\n\t";
|
|
|
|
}
|
|
|
|
return $deps;
|
|
|
|
}
|
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
sub get_deps {
|
2023-12-13 02:04:02 +00:00
|
|
|
my ($distdata, $data) = @_;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-12-13 02:04:02 +00:00
|
|
|
my $reqs = $distdata->{info}{requires_dist};
|
|
|
|
my %depends = ('py3-pytest' => 'py3-pytest');
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-12-13 02:04:02 +00:00
|
|
|
my @reqs =
|
|
|
|
map {
|
|
|
|
my $apkname = map_pypi_to_apk(s/(\(|\s+).*$//r);
|
|
|
|
$depends{$apkname} = $apkname
|
|
|
|
}
|
|
|
|
grep { $_ !~ m/; extra ==/ }
|
|
|
|
@$reqs;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-12-13 02:04:02 +00:00
|
|
|
my @checkdeps =
|
|
|
|
map {
|
|
|
|
my $apkname = map_pypi_to_apk(s/(\(|\s+).*$//r);
|
|
|
|
exists($depends{$apkname}) ? () : $apkname
|
|
|
|
}
|
|
|
|
grep { m/; extra == 'tests'/ }
|
|
|
|
@$reqs;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
|
|
|
my $apk = read_file('APKBUILD');
|
|
|
|
|
2023-12-13 02:15:57 +00:00
|
|
|
$reqs = format_depends(join ' ', @reqs);
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-12-13 02:04:02 +00:00
|
|
|
$apk =~ s/depends=""/depends="$reqs"/;
|
|
|
|
|
|
|
|
unshift @checkdeps, 'py3-pytest';
|
2023-12-13 02:15:57 +00:00
|
|
|
my $checkdeps = format_depends(join ' ', @checkdeps);
|
2023-12-13 02:04:02 +00:00
|
|
|
|
|
|
|
$apk =~ s/checkdepends="py3-pytest"/checkdepends="$checkdeps"/;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2021-01-23 20:43:26 +00:00
|
|
|
# remove empty variables
|
|
|
|
$apk =~ s/.*=""\n//g;
|
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
open my $fh, '>:utf8', 'APKBUILD';
|
|
|
|
|
|
|
|
print $fh $apk;
|
|
|
|
|
2023-12-13 02:04:02 +00:00
|
|
|
say "Requires: @reqs\n\nCheckDepends: @checkdeps";
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
my $abuild_conf = read_assignments_from_file('/etc/abuild.conf');
|
|
|
|
$packager = $abuild_conf->{PACKAGER} if $abuild_conf->{PACKAGER};
|
|
|
|
|
2019-08-04 01:28:00 +00:00
|
|
|
my $user_abuild_conf = read_assignments_from_file($ENV{"HOME"} . "/.abuild/abuild.conf");
|
|
|
|
$packager = $user_abuild_conf->{PACKAGER} if $user_abuild_conf->{PACKAGER};
|
|
|
|
|
2011-11-03 12:57:19 +00:00
|
|
|
sub usage {
|
|
|
|
say <<'EOF';
|
|
|
|
Usage: apkbuild-pypi [create <package> | check | recreate | upgrade | update]
|
|
|
|
|
|
|
|
In the repository root:
|
|
|
|
create <package>: Creates an APKBUILD for <package>
|
|
|
|
|
|
|
|
In the package root:
|
|
|
|
check : Reports current & latest version of the package
|
|
|
|
recreate : Recreates the APKBUILD
|
|
|
|
upgrade : Upgrades to the latest version of the package
|
|
|
|
update : Updates APKBUILD metadata
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
if (! defined $ARGV[0]) {
|
|
|
|
die usage;
|
|
|
|
} elsif ($ARGV[0] eq 'create') {
|
|
|
|
my $package = $ARGV[1];
|
|
|
|
$package or die usage;
|
|
|
|
|
|
|
|
my $distdata = get_data($package);
|
|
|
|
my $apkname = map_pypi_to_apk($package);
|
|
|
|
|
|
|
|
mkdir $apkname;
|
|
|
|
chdir $apkname;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
my $data = write_apkbuild($distdata, undef);
|
|
|
|
prepare_tree;
|
2021-01-23 01:17:41 +00:00
|
|
|
|
2023-12-13 02:04:02 +00:00
|
|
|
get_deps($distdata, $data);
|
2023-07-30 13:39:53 +00:00
|
|
|
} elsif ($ARGV[0] eq 'recreate') {
|
|
|
|
my $apkbuild = read_apkbuild;
|
|
|
|
if (! defined $apkbuild->{_pkgreal}) {
|
|
|
|
$apkbuild->{_pkgreal} = find_package_name($apkbuild);
|
|
|
|
}
|
|
|
|
my $distdata = get_data($apkbuild->{_pkgreal});
|
|
|
|
my $pkgver = $distdata->{info}{version} =~ s/^[^0-9]+//r;
|
|
|
|
if ($pkgver ne $apkbuild->{pkgver}) {
|
|
|
|
#Reset pkgrel on upgrade on recreate
|
|
|
|
say "Upgrading PyPI module from $apkbuild->{pkgver} to $pkgver";
|
|
|
|
$apkbuild->{pkgrel}=0;
|
|
|
|
}
|
|
|
|
my $data = write_apkbuild($distdata, $apkbuild);
|
2021-01-23 01:17:41 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
prepare_tree;
|
2023-12-13 02:04:02 +00:00
|
|
|
get_deps($distdata, $data);
|
2023-07-30 13:39:53 +00:00
|
|
|
} elsif ($ARGV[0] eq 'upgrade') {
|
|
|
|
my $apkbuild = read_apkbuild;
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
if (! defined $apkbuild->{_pkgreal}) {
|
|
|
|
$apkbuild->{_pkgreal} = find_package_name($apkbuild);
|
|
|
|
}
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
my $distdata = get_data($apkbuild->{_pkgreal});
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
my $pkgver = $distdata->{info}{version};
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
if ($pkgver ne $apkbuild->{pkgver}) {
|
|
|
|
say "Upgrading PyPI package from $apkbuild->{pkgver} to $pkgver";
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
my $text = read_file('APKBUILD');
|
2021-01-23 01:17:41 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
$text =~ s/^(pkgver)=.*$/$1=$pkgver/mg or
|
|
|
|
die "Can't find pkgver line in APKBUILD";
|
|
|
|
$text =~ s/^(pkgrel)=.*$/$1=0/mg or
|
|
|
|
die "Can't find pkgrel line in APKBUILD";
|
|
|
|
|
|
|
|
open my $fh, '>:utf8', 'APKBUILD';
|
|
|
|
print $fh $text;
|
|
|
|
close $fh;
|
|
|
|
} else {
|
|
|
|
say "Already up to date with PyPI";
|
|
|
|
}
|
|
|
|
} elsif ($ARGV[0] eq 'check') {
|
|
|
|
my $apkbuild = read_apkbuild;
|
|
|
|
|
|
|
|
if (! defined $apkbuild->{_pkgreal}) {
|
|
|
|
$apkbuild->{_pkgreal} = find_package_name($apkbuild);
|
|
|
|
}
|
|
|
|
my $distdata = get_data($apkbuild->{_pkgreal});
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
my $pkgver = $distdata->{info}{version};
|
2011-11-03 12:57:19 +00:00
|
|
|
|
2021-01-23 01:17:41 +00:00
|
|
|
|
2023-07-30 13:39:53 +00:00
|
|
|
say "$apkbuild->{pkgname}: Latest version: $pkgver Packaged version: $apkbuild->{pkgver}";
|
|
|
|
if ($pkgver ne $apkbuild->{pkgver}) {
|
|
|
|
exit(1);
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|
2023-07-30 13:39:53 +00:00
|
|
|
} elsif ($ARGV[0] eq 'update') {
|
|
|
|
prepare_tree;
|
|
|
|
} else {
|
|
|
|
die usage;
|
2011-11-03 12:57:19 +00:00
|
|
|
}
|