Also: - It's now installable by doing "nix-env -i nix-generate-from-cpan". - It maps dependencies to the correct attribute (e.g. HTML::HeadParser is mapped to HTMLParser). - It automatically selects buildPerlPackage or buildPerlModule. - It's documented in the manual.wip/yesman
parent
a79076b7aa
commit
629daa2102
@ -1,120 +0,0 @@ |
||||
#! /bin/sh -e |
||||
|
||||
name="$1" |
||||
[ -n "$name" ] || { echo "no name"; exit 1; } |
||||
|
||||
cpan -D "$name" > cpan-info |
||||
|
||||
url="$(echo $(cat cpan-info | sed '6!d'))" |
||||
[ -n "$url" ] || { echo "no URL"; exit 1; } |
||||
url="mirror://cpan/authors/id/$url" |
||||
echo "URL = $url" >&2 |
||||
|
||||
version=$(cat cpan-info | grep 'CPAN: ' | awk '{ print $2 }') |
||||
echo "VERSION = $version" |
||||
|
||||
declare -a xs=($(PRINT_PATH=1 nix-prefetch-url "$url")) |
||||
hash=${xs[0]} |
||||
path=${xs[1]} |
||||
echo "HASH = $hash" >&2 |
||||
|
||||
namedash="$(echo $name | sed s/::/-/g)-$version" |
||||
|
||||
attr=$(echo $name | sed s/:://g) |
||||
|
||||
rm -rf cpan_tmp |
||||
mkdir cpan_tmp |
||||
tar xf "$path" -C cpan_tmp |
||||
|
||||
shopt -s nullglob |
||||
meta=$(echo cpan_tmp/*/META.json) |
||||
if [ -z "$meta" ]; then |
||||
yaml=$(echo cpan_tmp/*/META.yml) |
||||
[ -n "$yaml" ] || { echo "no meta file"; exit 1; } |
||||
meta=$(echo $yaml | sed s/\.yml$/.json/) |
||||
perl -e ' |
||||
use YAML; |
||||
use JSON; |
||||
local $/; |
||||
$x = YAML::Load(<>); |
||||
print encode_json $x; |
||||
' < $yaml > $meta |
||||
fi |
||||
|
||||
description="$(json abstract < $meta | perl -e '$x = <>; print uc(substr($x, 0, 1)), substr($x, 1);')" |
||||
homepage="$(json resources.homepage < $meta)" |
||||
if [ -z "$homepage" ]; then |
||||
#homepage="$(json meta-spec.url < $meta)" |
||||
true |
||||
fi |
||||
|
||||
license="$(json license < $meta | json -a 2> /dev/null || true)" |
||||
if [ -z "$license" ]; then |
||||
license="$(json -a license < $meta)" |
||||
fi |
||||
license="$(echo $license | sed s/perl_5/perl5/)" |
||||
|
||||
f() { |
||||
local type="$1" |
||||
perl -e ' |
||||
use JSON; |
||||
local $/; |
||||
$x = decode_json <>; |
||||
if (defined $x->{prereqs}) { |
||||
$x2 = $x->{prereqs}->{'$type'}->{requires}; |
||||
} elsif ("'$type'" eq "runtime") { |
||||
$x2 = $x->{requires}; |
||||
} elsif ("'$type'" eq "configure") { |
||||
$x2 = $x->{configure_requires}; |
||||
} elsif ("'$type'" eq "build") { |
||||
$x2 = $x->{build_requires}; |
||||
} |
||||
foreach my $y (keys %{$x2}) { |
||||
next if $y eq "perl"; |
||||
eval "use $y;"; |
||||
if (!$@) { |
||||
print STDERR "skipping Perl-builtin module $y\n"; |
||||
next; |
||||
} |
||||
print $y, "\n"; |
||||
}; |
||||
' < $meta | sed s/:://g |
||||
} |
||||
|
||||
confdeps=$(f configure) |
||||
builddeps=$(f build) |
||||
testdeps=$(f test) |
||||
runtimedeps=$(f runtime) |
||||
|
||||
buildInputs=$(echo $(for i in $confdeps $builddeps $testdeps; do echo $i; done | sort | uniq)) |
||||
propagatedBuildInputs=$(echo $(for i in $runtimedeps; do echo $i; done | sort | uniq)) |
||||
|
||||
echo "===" >&2 |
||||
|
||||
cat <<EOF |
||||
$attr = buildPerlPackage { |
||||
name = "$namedash"; |
||||
src = fetchurl { |
||||
url = $url; |
||||
sha256 = "$hash"; |
||||
}; |
||||
EOF |
||||
if [ -n "$buildInputs" ]; then |
||||
cat <<EOF |
||||
buildInputs = [ $buildInputs ]; |
||||
EOF |
||||
fi |
||||
if [ -n "$propagatedBuildInputs" ]; then |
||||
cat <<EOF |
||||
propagatedBuildInputs = [ $propagatedBuildInputs ]; |
||||
EOF |
||||
fi |
||||
cat <<EOF |
||||
meta = { |
||||
homepage = $homepage; |
||||
description = "$description"; |
||||
license = "$license"; |
||||
}; |
||||
}; |
||||
EOF |
||||
|
@ -0,0 +1,22 @@ |
||||
{ stdenv, makeWrapper, perl, perlPackages }: |
||||
|
||||
stdenv.mkDerivation { |
||||
name = "nix-generate-from-cpan-1"; |
||||
|
||||
buildInputs = [ makeWrapper perl perlPackages.YAML perlPackages.JSON ]; |
||||
|
||||
unpackPhase = "true"; |
||||
buildPhase = "true"; |
||||
|
||||
installPhase = |
||||
'' |
||||
mkdir -p $out/bin |
||||
cp ${./nix-generate-from-cpan.pl} $out/bin/nix-generate-from-cpan |
||||
wrapProgram $out/bin/nix-generate-from-cpan --set PERL5LIB $PERL5LIB |
||||
''; |
||||
|
||||
meta = { |
||||
maintainers = [ stdenv.lib.maintainers.eelco ]; |
||||
description = "Utility to generate a Nix expression for a Perl package from CPAN"; |
||||
}; |
||||
} |
@ -0,0 +1,162 @@ |
||||
#! /run/current-system/sw/bin/perl -w |
||||
|
||||
use strict; |
||||
use CPANPLUS::Backend; |
||||
use YAML; |
||||
use JSON; |
||||
|
||||
my $module_name = $ARGV[0]; |
||||
die "syntax: $0 <MODULE-NAME>\n" unless defined $module_name; |
||||
|
||||
my $cb = CPANPLUS::Backend->new; |
||||
|
||||
my @modules = $cb->search(type => "name", allow => [$module_name]); |
||||
die "module $module_name not found\n" if scalar @modules == 0; |
||||
die "multiple packages that match module $module_name\n" if scalar @modules > 1; |
||||
my $module = $modules[0]; |
||||
|
||||
sub pkg_to_attr { |
||||
my ($pkg_name) = @_; |
||||
my $attr_name = $pkg_name; |
||||
$attr_name =~ s/-\d.*//; # strip version |
||||
return "LWP" if $attr_name eq "libwww-perl"; |
||||
$attr_name =~ s/-//g; |
||||
return $attr_name; |
||||
} |
||||
|
||||
sub get_pkg_name { |
||||
my ($module) = @_; |
||||
my $pkg_name = $module->package; |
||||
$pkg_name =~ s/\.tar.*//; |
||||
$pkg_name =~ s/\.zip//; |
||||
return $pkg_name; |
||||
} |
||||
|
||||
my $pkg_name = get_pkg_name $module; |
||||
my $attr_name = pkg_to_attr $pkg_name; |
||||
|
||||
print STDERR "attribute name: ", $attr_name, "\n"; |
||||
print STDERR "module: ", $module->module, "\n"; |
||||
print STDERR "version: ", $module->version, "\n"; |
||||
print STDERR "package: ", $module->package, , " (", $pkg_name, ", ", $attr_name, ")\n"; |
||||
print STDERR "path: ", $module->path, "\n"; |
||||
|
||||
my $tar_path = $module->fetch(); |
||||
print STDERR "downloaded to: $tar_path\n"; |
||||
print STDERR "sha-256: ", $module->status->checksum_value, "\n"; |
||||
|
||||
my $pkg_path = $module->extract(); |
||||
print STDERR "unpacked to: $pkg_path\n"; |
||||
|
||||
my $meta; |
||||
if (-e "$pkg_path/META.yml") { |
||||
$meta = YAML::LoadFile("$pkg_path/META.yml"); |
||||
} |
||||
|
||||
print STDERR "metadata: ", encode_json($meta), "\n"; |
||||
|
||||
# Map a module to the attribute corresponding to its package |
||||
# (e.g. HTML::HeadParser will be mapped to HTMLParser, because that |
||||
# module is in the HTML-Parser package). |
||||
sub module_to_pkg { |
||||
my ($module_name) = @_; |
||||
my @modules = $cb->search(type => "name", allow => [$module_name]); |
||||
if (scalar @modules == 0) { |
||||
# Fallback. |
||||
$module_name =~ s/:://g; |
||||
return $module_name; |
||||
} |
||||
my $module = $modules[0]; |
||||
my $attr_name = pkg_to_attr(get_pkg_name $module); |
||||
print STDERR "mapped dep $module_name to $attr_name\n"; |
||||
return $attr_name; |
||||
} |
||||
|
||||
sub get_deps { |
||||
my ($type) = @_; |
||||
my $deps; |
||||
if (defined $meta->{prereqs}) { |
||||
die "unimplemented"; |
||||
} elsif ($type eq "runtime") { |
||||
$deps = $meta->{requires}; |
||||
} elsif ($type eq "configure") { |
||||
$deps = $meta->{configure_requires}; |
||||
} elsif ($type eq "build") { |
||||
$deps = $meta->{build_requires}; |
||||
} |
||||
my @res; |
||||
foreach my $n (keys %{$deps}) { |
||||
next if $n eq "perl"; |
||||
# Hacky way to figure out if this module is part of Perl. |
||||
if ($n !~ /^JSON/ && $n !~ /^YAML/) { |
||||
eval "use $n;"; |
||||
if (!$@) { |
||||
print STDERR "skipping Perl-builtin module $n\n"; |
||||
next; |
||||
} |
||||
} |
||||
push @res, module_to_pkg($n); |
||||
} |
||||
return @res; |
||||
} |
||||
|
||||
sub uniq { |
||||
return keys %{{ map { $_ => 1 } @_ }}; |
||||
} |
||||
|
||||
my @build_deps = sort(uniq(get_deps("configure"), get_deps("build"), get_deps("test"))); |
||||
print STDERR "build deps: @build_deps\n"; |
||||
|
||||
my @runtime_deps = sort(uniq(get_deps("runtime"))); |
||||
print STDERR "runtime deps: @runtime_deps\n"; |
||||
|
||||
my $homepage = $meta->{resources}->{homepage}; |
||||
print STDERR "homepage: $homepage\n" if defined $homepage; |
||||
|
||||
my $description = $meta->{abstract}; |
||||
$description = uc(substr($description, 0, 1)) . substr($description, 1); # capitalise first letter |
||||
$description =~ s/\.$//; # remove period at the end |
||||
$description =~ s/\s*$//; |
||||
$description =~ s/^\s*//; |
||||
print STDERR "description: $description\n"; |
||||
|
||||
my $license = $meta->{license}; |
||||
if (defined $license) { |
||||
$license = "perl5" if $license eq "perl_5"; |
||||
print STDERR "license: $license\n"; |
||||
} |
||||
|
||||
my $build_fun = -e "$pkg_path/Build.PL" && ! -e "$pkg_path/Makefile.PL" ? "buildPerlModule" : "buildPerlPackage"; |
||||
|
||||
print STDERR "===\n"; |
||||
|
||||
print <<EOF; |
||||
$attr_name = $build_fun { |
||||
name = "$pkg_name"; |
||||
src = fetchurl { |
||||
url = mirror://cpan/${\$module->path}/${\$module->package}; |
||||
sha256 = "${\$module->status->checksum_value}"; |
||||
}; |
||||
EOF |
||||
print <<EOF if scalar @build_deps > 0; |
||||
buildInputs = [ @build_deps ]; |
||||
EOF |
||||
print <<EOF if scalar @runtime_deps > 0; |
||||
propagatedBuildInputs = [ @runtime_deps ]; |
||||
EOF |
||||
print <<EOF; |
||||
meta = { |
||||
EOF |
||||
print <<EOF if defined $homepage; |
||||
homepage = $homepage; |
||||
EOF |
||||
print <<EOF; |
||||
description = "$description"; |
||||
EOF |
||||
print <<EOF if defined $license; |
||||
license = "$license"; |
||||
EOF |
||||
print <<EOF; |
||||
}; |
||||
}; |
||||
EOF |
Loading…
Reference in new issue