1#! /run/current-system/sw/bin/perl -w
2
3use strict;
4use CPANPLUS::Backend;
5use YAML::XS;
6use JSON;
7
8my $module_name = $ARGV[0];
9die "syntax: $0 <MODULE-NAME>\n" unless defined $module_name;
10
11my $cb = CPANPLUS::Backend->new;
12
13my @modules = $cb->search(type => "name", allow => [$module_name]);
14die "module $module_name not found\n" if scalar @modules == 0;
15die "multiple packages that match module $module_name\n" if scalar @modules > 1;
16my $module = $modules[0];
17
18sub pkg_to_attr {
19 my ($pkg_name) = @_;
20 my $attr_name = $pkg_name;
21 $attr_name =~ s/-\d.*//; # strip version
22 return "LWP" if $attr_name eq "libwww-perl";
23 $attr_name =~ s/-//g;
24 return $attr_name;
25}
26
27sub get_pkg_name {
28 my ($module) = @_;
29 my $pkg_name = $module->package;
30 $pkg_name =~ s/\.tar.*//;
31 $pkg_name =~ s/\.zip//;
32 return $pkg_name;
33}
34
35my $pkg_name = get_pkg_name $module;
36my $attr_name = pkg_to_attr $pkg_name;
37
38print STDERR "attribute name: ", $attr_name, "\n";
39print STDERR "module: ", $module->module, "\n";
40print STDERR "version: ", $module->version, "\n";
41print STDERR "package: ", $module->package, , " (", $pkg_name, ", ", $attr_name, ")\n";
42print STDERR "path: ", $module->path, "\n";
43
44my $tar_path = $module->fetch();
45print STDERR "downloaded to: $tar_path\n";
46print STDERR "sha-256: ", $module->status->checksum_value, "\n";
47
48my $pkg_path = $module->extract();
49print STDERR "unpacked to: $pkg_path\n";
50
51my $meta;
52if (-e "$pkg_path/META.yml") {
53 eval {
54 $meta = YAML::XS::LoadFile("$pkg_path/META.yml");
55 };
56 if ($@) {
57 system("iconv -f windows-1252 -t utf-8 '$pkg_path/META.yml' > '$pkg_path/META.yml.tmp'");
58 $meta = YAML::XS::LoadFile("$pkg_path/META.yml.tmp");
59 }
60} elsif (-e "$pkg_path/META.json") {
61 local $/;
62 open(my $fh, '<', "$pkg_path/META.json") or die;
63 $meta = decode_json(<$fh>);
64} else {
65 warn "package has no META.yml or META.json\n";
66}
67
68print STDERR "metadata: ", encode_json($meta), "\n" if defined $meta;
69
70# Map a module to the attribute corresponding to its package
71# (e.g. HTML::HeadParser will be mapped to HTMLParser, because that
72# module is in the HTML-Parser package).
73sub module_to_pkg {
74 my ($module_name) = @_;
75 my @modules = $cb->search(type => "name", allow => [$module_name]);
76 if (scalar @modules == 0) {
77 # Fallback.
78 $module_name =~ s/:://g;
79 return $module_name;
80 }
81 my $module = $modules[0];
82 my $attr_name = pkg_to_attr(get_pkg_name $module);
83 print STDERR "mapped dep $module_name to $attr_name\n";
84 return $attr_name;
85}
86
87sub get_deps {
88 my ($type) = @_;
89 my $deps;
90 if (defined $meta->{prereqs}) {
91 die "unimplemented";
92 } elsif ($type eq "runtime") {
93 $deps = $meta->{requires};
94 } elsif ($type eq "configure") {
95 $deps = $meta->{configure_requires};
96 } elsif ($type eq "build") {
97 $deps = $meta->{build_requires};
98 }
99 my @res;
100 foreach my $n (keys %{$deps}) {
101 next if $n eq "perl";
102 # Hacky way to figure out if this module is part of Perl.
103 if ($n !~ /^JSON/ && $n !~ /^YAML/ && $n !~ /^Module::Pluggable/) {
104 eval "use $n;";
105 if (!$@) {
106 print STDERR "skipping Perl-builtin module $n\n";
107 next;
108 }
109 }
110 push @res, module_to_pkg($n);
111 }
112 return @res;
113}
114
115sub uniq {
116 return keys %{{ map { $_ => 1 } @_ }};
117}
118
119my @build_deps = sort(uniq(get_deps("configure"), get_deps("build"), get_deps("test")));
120print STDERR "build deps: @build_deps\n";
121
122my @runtime_deps = sort(uniq(get_deps("runtime")));
123print STDERR "runtime deps: @runtime_deps\n";
124
125my $homepage = $meta->{resources}->{homepage};
126print STDERR "homepage: $homepage\n" if defined $homepage;
127
128my $description = $meta->{abstract};
129if (defined $description) {
130 $description = uc(substr($description, 0, 1)) . substr($description, 1); # capitalise first letter
131 $description =~ s/\.$//; # remove period at the end
132 $description =~ s/\s*$//;
133 $description =~ s/^\s*//;
134 print STDERR "description: $description\n";
135}
136
137my $license = $meta->{license};
138if (defined $license) {
139 $license = "perl5" if $license eq "perl_5";
140 print STDERR "license: $license\n";
141}
142
143my $build_fun = -e "$pkg_path/Build.PL" && ! -e "$pkg_path/Makefile.PL" ? "buildPerlModule" : "buildPerlPackage";
144
145print STDERR "===\n";
146
147print <<EOF;
148 $attr_name = $build_fun {
149 name = "$pkg_name";
150 src = fetchurl {
151 url = mirror://cpan/${\$module->path}/${\$module->package};
152 sha256 = "${\$module->status->checksum_value}";
153 };
154EOF
155print <<EOF if scalar @build_deps > 0;
156 buildInputs = [ @build_deps ];
157EOF
158print <<EOF if scalar @runtime_deps > 0;
159 propagatedBuildInputs = [ @runtime_deps ];
160EOF
161print <<EOF;
162 meta = {
163EOF
164print <<EOF if defined $homepage;
165 homepage = $homepage;
166EOF
167print <<EOF if defined $description;
168 description = "$description";
169EOF
170print <<EOF if defined $license;
171 license = "$license";
172EOF
173print <<EOF;
174 };
175 };
176EOF