JapaChar/cpan.pl

142 lines
3.3 KiB
Perl

#!/usr/bin/env perl
use v5.14;
use strict;
use warnings;
use Digest::SHA;
require File::Temp;
use File::Temp ();
use Getopt::Long::Descriptive;
use JSON::MaybeXS;
use LWP::UserAgent;
use MetaCPAN::Client;
use Capture::Tiny qw(tee);
sub scan_deps {
my @deps = grep(/^Successfully installed/, @_);
for (@deps)
{
s/^Successfully installed (\S+).*/$1/;
}
@deps
}
sub get_url_sha256 {
my ($url) = @_;
my $state = Digest::SHA->new(256);
my $ua = LWP::UserAgent->new;
$ua->env_proxy;
my $resp = $ua->get($url, ':read_size_hint' => 1024,
':content_cb' => sub {
my ($data) = @_;
$state->add($data);
});
die "Failed to get sha256 of $url: @{[$resp->status_line]}\n" if !$resp->is_success;
$state->hexdigest;
}
sub get_source_for_dep {
my ($cpan, $dep, $outdir) = @_;
my $release_set = $cpan->release({ name => $dep });
die "Unexpected @{[$release_set->total]} releases for $dep"
if $release_set->total != 1;
my $release = $release_set->next;
my $url = $release->download_url;
my $sha256 = get_url_sha256 $url;
{
type => 'archive',
url => $url,
sha256 => $sha256,
dest => "$outdir/@{[$release->distribution]}",
};
}
sub write_module_to_file {
my ($output, $root) = @_;
my $serializer = JSON::MaybeXS->new(indent => 1, space_after => 1, canonical => 1);
my $json = $serializer->encode($root);
open my $fh, '>', $output or die "Could not open $output for writing\n";
print $fh $json;
close $fh;
}
sub main {
my ($opts, $usage) = describe_options(
'flatpak-cpan-generator %o <packages...>',
['output|o=s', 'The generated sources file', { default => 'generated-sources.json' }],
['dir|d=s', 'The output directory used inside the sources file', { default => 'perl-libs' }],
['help|h', 'Show this screen', { shortcircuit => 1, hidden => 1 }],
);
if ($opts->help) {
print $usage->text;
exit;
}
die "At least one package is required.\n" if @ARGV == 0;
my $cpan = MetaCPAN::Client->new;
say '** Installing dependencies with cpanm...';
my $tmpdir = File::Temp->newdir;
my ($stdout, $stderr, $exit) = tee {
system ('cpanm', '-n', '-L', $tmpdir, "--", @ARGV);
};
die "cpanm failed with exit status $exit\n" if $exit != 0;
say '** Scanning dependencies...';
my @stdout = split "\n", $stdout;
my @deps = scan_deps @stdout;
# my @deps = scan_deps 'lib';
my @sources = ();
foreach my $dep (@deps) {
say "** Processing: $dep";
my $source = get_source_for_dep $cpan, $dep, $opts->dir;
push @sources, $source;
}
push @sources, {
type => 'script',
dest => $opts->dir,
'dest-filename' => 'install.sh',
commands => [
"set -e",
"function make_install {",
" mod_dir=\$1",
" cd \$mod_dir",
" if [ -f 'Makefile.PL' ]; then",
" perl Makefile.PL PREFIX=\${FLATPAK_DEST} && make install PREFIX=\${FLATPAK_DEST}",
" elif [ -f 'Build.PL' ]; then",
" perl Build.PL && ./Build && ./Build install",
" else",
" echo 'No Makefile.PL or Build.PL found. Do not know how to install this module'",
" exit 1",
" fi",
"}",
map { "(make_install $_->{dest})" } @sources
],
};
write_module_to_file $opts->output, \@sources;
}
main;