]> rtime.felk.cvut.cz Git - coffee/buildroot.git/blob - utils/scancpan
support/kconfig: Add missing target to README.buildroot
[coffee/buildroot.git] / utils / scancpan
1 #!/usr/bin/env perl
2
3 # This chunk of stuff was generated by App::FatPacker. To find the original
4 # file's code, look for the end of this BEGIN block or the string 'FATPACK'
5 BEGIN {
6 my %fatpacked;
7
8 $fatpacked{"MetaCPAN/API/Tiny.pm"} = <<'METACPAN_API_TINY';
9   package MetaCPAN::API::Tiny;
10   {
11     $MetaCPAN::API::Tiny::VERSION = '1.131730';
12   }
13   use strict;
14   use warnings;
15   # ABSTRACT: A Tiny API client for MetaCPAN
16
17   use Carp;
18   use JSON::PP 'encode_json', 'decode_json';
19   use HTTP::Tiny;
20
21
22   sub new {
23       my ($class, @args) = @_;
24
25       $#_ % 2 == 0
26           or croak 'Arguments must be provided as name/value pairs';
27
28       my %params = @args;
29
30       die 'ua_args must be an array reference'
31           if $params{ua_args} && ref($params{ua_args}) ne 'ARRAY';
32
33       my $self = +{
34           base_url => $params{base_url} || 'http://api.metacpan.org/v0',
35           ua => $params{ua} || HTTP::Tiny->new(
36               $params{ua_args}
37                   ? @{$params{ua_args}}
38                   : (agent => 'MetaCPAN::API::Tiny/'
39                       . ($MetaCPAN::API::VERSION || 'xx'))),
40       };
41
42       return bless($self, $class);
43   }
44
45   sub _build_extra_params {
46       my $self = shift;
47
48       @_ % 2 == 0
49           or croak 'Incorrect number of params, must be key/value';
50
51       my %extra = @_;
52       my $ua = $self->{ua};
53
54       foreach my $key (keys %extra)
55       {
56           # The implementation in HTTP::Tiny uses + instead of %20, fix that
57           $extra{$key} = $ua->_uri_escape($extra{$key});
58           $extra{$key} =~ s/\+/%20/g;
59       }
60
61       my $params = join '&', map { "$_=" . $extra{$_} } sort keys %extra;
62
63       return $params;
64   }
65
66
67   # /source/{author}/{release}/{path}
68   sub source {
69       my $self  = shift;
70       my %opts  = @_ ? @_ : ();
71       my $url   = '';
72       my $error = "Provide 'author' and 'release' and 'path'";
73
74       %opts or croak $error;
75
76       if (
77           defined ( my $author  = $opts{'author'}  ) &&
78           defined ( my $release = $opts{'release'} ) &&
79           defined ( my $path    = $opts{'path'}    )
80         ) {
81           $url = "source/$author/$release/$path";
82       } else {
83           croak $error;
84       }
85
86       $url = $self->{base_url} . "/$url";
87
88       my $result = $self->{ua}->get($url);
89       $result->{'success'}
90           or croak "Failed to fetch '$url': " . $result->{'reason'};
91
92       return $result->{'content'};
93   }
94
95
96   # /release/{distribution}
97   # /release/{author}/{release}
98   sub release {
99       my $self  = shift;
100       my %opts  = @_ ? @_ : ();
101       my $url   = '';
102       my $error = "Either provide 'distribution', or 'author' and 'release', " .
103                   "or 'search'";
104
105       %opts or croak $error;
106
107       my %extra_opts = ();
108
109       if ( defined ( my $dist = $opts{'distribution'} ) ) {
110           $url = "release/$dist";
111       } elsif (
112           defined ( my $author  = $opts{'author'}  ) &&
113           defined ( my $release = $opts{'release'} )
114         ) {
115           $url = "release/$author/$release";
116       } elsif ( defined ( my $search_opts = $opts{'search'} ) ) {
117           ref $search_opts && ref $search_opts eq 'HASH'
118               or croak $error;
119
120           %extra_opts = %{$search_opts};
121           $url        = 'release/_search';
122       } else {
123           croak $error;
124       }
125
126       return $self->fetch( $url, %extra_opts );
127   }
128
129
130   # /pod/{module}
131   # /pod/{author}/{release}/{path}
132   sub pod {
133       my $self  = shift;
134       my %opts  = @_ ? @_ : ();
135       my $url   = '';
136       my $error = "Either provide 'module' or 'author and 'release' and 'path'";
137
138       %opts or croak $error;
139
140       if ( defined ( my $module = $opts{'module'} ) ) {
141           $url = "pod/$module";
142       } elsif (
143           defined ( my $author  = $opts{'author'}  ) &&
144           defined ( my $release = $opts{'release'} ) &&
145           defined ( my $path    = $opts{'path'}    )
146         ) {
147           $url = "pod/$author/$release/$path";
148       } else {
149           croak $error;
150       }
151
152       # check content-type
153       my %extra = ();
154       if ( defined ( my $type = $opts{'content-type'} ) ) {
155           $type =~ m{^ text/ (?: html|plain|x-pod|x-markdown ) $}x
156               or croak 'Incorrect content-type provided';
157
158           $extra{headers}{'content-type'} = $type;
159       }
160
161       $url = $self->{base_url}. "/$url";
162
163       my $result = $self->{ua}->get( $url, \%extra );
164       $result->{'success'}
165           or croak "Failed to fetch '$url': " . $result->{'reason'};
166
167       return $result->{'content'};
168   }
169
170
171   # /module/{module}
172   sub module {
173       my $self = shift;
174       my $name = shift;
175
176       $name or croak 'Please provide a module name';
177
178       return $self->fetch("module/$name");
179   }
180
181
182   # file() is a synonym of module
183   sub file { goto &module }
184
185
186   # /author/{author}
187   sub author {
188       my $self = shift;
189       my ( $pause_id, $url, %extra_opts );
190
191       if ( @_ == 1 ) {
192           $url = 'author/' . shift;
193       } elsif ( @_ == 2 ) {
194           my %opts = @_;
195
196           if ( defined $opts{'pauseid'} ) {
197               $url = "author/" . $opts{'pauseid'};
198           } elsif ( defined $opts{'search'} ) {
199               my $search_opts = $opts{'search'};
200
201               ref $search_opts && ref $search_opts eq 'HASH'
202                   or croak "'search' key must be hashref";
203
204               %extra_opts = %{$search_opts};
205               $url        = 'author/_search';
206           } else {
207               croak 'Unknown option given';
208           }
209       } else {
210           croak 'Please provide an author PAUSEID or a "search"';
211       }
212
213       return $self->fetch( $url, %extra_opts );
214   }
215
216
217
218   sub fetch {
219       my $self    = shift;
220       my $url     = shift;
221       my $extra   = $self->_build_extra_params(@_);
222       my $base    = $self->{base_url};
223       my $req_url = $extra ? "$base/$url?$extra" : "$base/$url";
224
225       my $result  = $self->{ua}->get($req_url);
226       return $self->_decode_result( $result, $req_url );
227   }
228
229
230   sub post {
231       my $self  = shift;
232       my $url   = shift;
233       my $query = shift;
234       my $base  = $self->{base_url};
235
236       defined $url
237           or croak 'First argument of URL must be provided';
238
239       ref $query and ref $query eq 'HASH'
240           or croak 'Second argument of query hashref must be provided';
241
242       my $query_json = encode_json( $query );
243       my $result     = $self->{ua}->request(
244           'POST',
245           "$base/$url",
246           {
247               headers => { 'Content-Type' => 'application/json' },
248               content => $query_json,
249           }
250       );
251
252       return $self->_decode_result( $result, $url, $query_json );
253   }
254
255   sub _decode_result {
256       my $self = shift;
257       my ( $result, $url, $original ) = @_;
258       my $decoded_result;
259
260       ref $result and ref $result eq 'HASH'
261           or croak 'First argument must be hashref';
262
263       defined $url
264           or croak 'Second argument of a URL must be provided';
265
266       if ( defined ( my $success = $result->{'success'} ) ) {
267           my $reason = $result->{'reason'} || '';
268           $reason .= ( defined $original ? " (request: $original)" : '' );
269
270           $success or croak "Failed to fetch '$url': $reason";
271       } else {
272           croak 'Missing success in return value';
273       }
274
275       defined ( my $content = $result->{'content'} )
276           or croak 'Missing content in return value';
277
278       eval { $decoded_result = decode_json $content; 1 }
279       or do { croak "Couldn't decode '$content': $@" };
280
281       return $decoded_result;
282   }
283
284   1;
285
286   __END__
287
288   =pod
289
290   =head1 NAME
291
292   MetaCPAN::API::Tiny - A Tiny API client for MetaCPAN
293
294   =head1 VERSION
295
296   version 1.131730
297
298   =head1 DESCRIPTION
299
300   This is the Tiny version of L<MetaCPAN::API>. It implements a compatible API
301   with a few notable exceptions:
302
303   =over 4
304
305   =item Attributes are direct hash access
306
307   The attributes defined using Mo(o|u)se are now accessed via the blessed hash
308   directly. There are no accessors defined to access this elements.
309
310   =item Exception handling
311
312   Instead of using Try::Tiny, raw evals are used. This could potentially cause
313   issues, so just be aware.
314
315   =item Testing
316
317   Test::Fatal was replaced with an eval implementation of exception().
318   Test::TinyMocker usage is retained, but may be absorbed since it is pure perl
319
320   =back
321
322   =head1 CLASS_METHODS
323
324   =head2 new
325
326   new is the constructor for MetaCPAN::API::Tiny. In the non-tiny version of this
327   module, this is provided via Any::Moose built from the attributes defined. In
328   the tiny version, we define our own constructor. It takes the same arguments
329   and provides similar checks to MetaCPAN::API with regards to arguments passed.
330
331   =head1 PUBLIC_METHODS
332
333   =head2 source
334
335       my $source = $mcpan->source(
336           author  => 'DOY',
337           release => 'Moose-2.0201',
338           path    => 'lib/Moose.pm',
339       );
340
341   Searches MetaCPAN for a module or a specific release and returns the plain source.
342
343   =head2 release
344
345       my $result = $mcpan->release( distribution => 'Moose' );
346
347       # or
348       my $result = $mcpan->release( author => 'DOY', release => 'Moose-2.0001' );
349
350   Searches MetaCPAN for a dist.
351
352   You can do complex searches using 'search' parameter:
353
354       # example lifted from MetaCPAN docs
355       my $result = $mcpan->release(
356           search => {
357               author => "OALDERS AND ",
358               filter => "status:latest",
359               fields => "name",
360               size   => 1,
361           },
362       );
363
364   =head2 pod
365
366       my $result = $mcpan->pod( module => 'Moose' );
367
368       # or
369       my $result = $mcpan->pod(
370           author  => 'DOY',
371           release => 'Moose-2.0201',
372           path    => 'lib/Moose.pm',
373       );
374
375   Searches MetaCPAN for a module or a specific release and returns the POD.
376
377   =head2 module
378
379       my $result = $mcpan->module('MetaCPAN::API');
380
381   Searches MetaCPAN and returns a module's ".pm" file.
382
383   =head2 file
384
385   A synonym of L</module>
386
387   =head2 author
388
389       my $result1 = $mcpan->author('XSAWYERX');
390       my $result2 = $mcpan->author( pauseid => 'XSAWYERX' );
391
392   Searches MetaCPAN for a specific author.
393
394   You can do complex searches using 'search' parameter:
395
396       # example lifted from MetaCPAN docs
397       my $result = $mcpan->author(
398           search => {
399               q    => 'profile.name:twitter',
400               size => 1,
401           },
402       );
403
404   =head2 fetch
405
406       my $result = $mcpan->fetch('/release/distribution/Moose');
407
408       # with parameters
409       my $more = $mcpan->fetch(
410           '/release/distribution/Moose',
411           param => 'value',
412       );
413
414   This is a helper method for API implementations. It fetches a path from MetaCPAN, decodes the JSON from the content variable and returns it.
415
416   You don't really need to use it, but you can in case you want to write your own extension implementation to MetaCPAN::API.
417
418   It accepts an additional hash as "GET" parameters.
419
420   =head2 post
421
422       # /release&content={"query":{"match_all":{}},"filter":{"prefix":{"archive":"Cache-Cache-1.06"}}}
423       my $result = $mcpan->post(
424           'release',
425           {
426               query  => { match_all => {} },
427               filter => { prefix => { archive => 'Cache-Cache-1.06' } },
428           },
429       );
430
431   The POST equivalent of the "fetch()" method. It gets the path and JSON request.
432
433   =head1 THANKS
434
435   Overall the tests and code were ripped directly from MetaCPAN::API and
436   tiny-fied. A big thanks to Sawyer X for writing the original module.
437
438   =head1 AUTHOR
439
440   Nicholas R. Perez <nperez@cpan.org>
441
442   =head1 COPYRIGHT AND LICENSE
443
444   This software is copyright (c) 2013 by Nicholas R. Perez <nperez@cpan.org>.
445
446   This is free software; you can redistribute it and/or modify it under
447   the same terms as the Perl 5 programming language system itself.
448
449   =cut
450 METACPAN_API_TINY
451
452 s/^  //mg for values %fatpacked;
453
454 unshift @INC, sub {
455   if (my $fat = $fatpacked{$_[1]}) {
456     if ($] < 5.008) {
457       return sub {
458         return 0 unless length $fat;
459         $fat =~ s/^([^\n]*\n?)//;
460         $_ = $1;
461         return 1;
462       };
463     }
464     open my $fh, '<', \$fat
465       or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
466     return $fh;
467   }
468   return
469 };
470
471 } # END OF FATPACK CODE
472
473
474 use 5.010;
475 use strict;
476 use warnings;
477 use Fatal qw(open close);
478
479 use Getopt::Long;
480 use Pod::Usage;
481 use File::Basename;
482 use Module::CoreList;
483 use HTTP::Tiny;
484 use Safe;
485 use MetaCPAN::API::Tiny;
486
487 # Below, 5.026 should be aligned with the version of perl actually
488 # bundled in Buildroot:
489 die <<"MSG" if $] < 5.026;
490 This script needs a host perl with the same major version as Buildroot target perl.
491
492 Your current host perl is:
493     $^X
494     version $]
495
496 You may install a local one by running:
497     perlbrew install perl-5.26.0
498 MSG
499
500 my ($help, $man, $quiet, $force, $recommend, $test, $host);
501 my $target = 1;
502 GetOptions( 'help|?' => \$help,
503             'man' => \$man,
504             'quiet|q' => \$quiet,
505             'force|f' => \$force,
506             'host!' => \$host,
507             'target!' => \$target,
508             'recommend' => \$recommend,
509             'test' => \$test
510 ) or pod2usage(-exitval => 1);
511 pod2usage(-exitval => 0) if $help;
512 pod2usage(-exitval => 0, -verbose => 2) if $man;
513 pod2usage(-exitval => 1) if scalar @ARGV == 0;
514
515 my %dist;               # name -> metacpan data
516 my %need_target;        # name -> 1 if target package is needed
517 my %need_host;          # name -> 1 if host package is needed
518 my %need_dlopen;        # name -> 1 if requires dynamic library
519 my %deps_build;         # name -> list of host dependencies
520 my %deps_runtime;       # name -> list of target dependencies
521 my %deps_optional;      # name -> list of optional target dependencies
522 my %license_files;      # name -> list of license files
523 my %checksum;           # author -> list of checksum
524 my $mirror = 'http://cpan.metacpan.org';        # a CPAN mirror
525 my $mcpan = MetaCPAN::API::Tiny->new(base_url => 'http://fastapi.metacpan.org/v1');
526 my $ua = HTTP::Tiny->new();
527
528 sub get_checksum {
529     my ($url) = @_;
530     my ($path) = $url =~ m|^[^:/?#]+://[^/?#]*([^?#]*)|;
531     my ($basename, $dirname) = fileparse( $path );
532     unless ($checksum{$dirname}) {
533         my $url = $mirror . $dirname . q{CHECKSUMS};
534         my $response = $ua->get($url);
535         $checksum{$dirname} = $response->{content};
536     }
537     my $chksum = Safe->new->reval($checksum{$dirname});
538     return $chksum->{$basename}, $basename;
539 }
540
541 sub is_xs {
542     my ($manifest) = @_;
543     # This heuristic determines if a module is a native extension, by searching
544     # some file extension types in the MANIFEST of the distribution.
545     # It was inspired by http://deps.cpantesters.org/static/purity.html
546     return $manifest =~ m/\.(swg|xs|c|h|i)[\n\s]/;
547 }
548
549 sub find_license_files {
550     my ($manifest) = @_;
551     my @license_files;
552     foreach (split /\n/, $manifest) {
553         next if m|/|;
554         push @license_files, $_ if m/(ARTISTIC|COPYING|COPYRIGHT|LICENSE)/i;
555     }
556     if (scalar @license_files == 0 && $manifest =~ m/(README)[\n\s]/i) {
557         @license_files = ($1);
558     }
559     return \@license_files;
560 }
561
562 sub fetch {
563     my ($name, $need_target, $need_host, $top) = @_;
564     $need_target{$name} = $need_target if $need_target;
565     $need_host{$name} = $need_host if $need_host;
566     unless ($dist{$name} && !$top) {
567         say qq{fetch ${name}} unless $quiet;
568         my $result = $mcpan->release( distribution => $name );
569         $dist{$name} = $result;
570         eval {
571             my $manifest = $mcpan->source( author => $result->{author},
572                                            release => $name . q{-} . $result->{version},
573                                            path => 'MANIFEST' );
574             $need_dlopen{$name} = is_xs( $manifest );
575             $license_files{$name} = find_license_files( $manifest );
576         };
577         if ($@) {
578             warn $@;
579             $license_files{$name} = [];
580         }
581         my %build = ();
582         my %runtime = ();
583         my %optional = ();
584         foreach my $dep (@{$result->{dependency}}) {
585             my $modname = ${$dep}{module};
586             next if $modname eq q{perl};
587             next if $modname =~ m|^Alien|;
588             next if $modname =~ m|^Win32|;
589             next if !($test && $top) && $modname =~ m|^Test|;
590             next if Module::CoreList::is_core( $modname, undef, $] );
591             # we could use the host Module::CoreList data, because host perl and
592             # target perl have the same major version
593             next if ${$dep}{phase} eq q{develop};
594             next if !($test && $top) && ${$dep}{phase} eq q{test};
595             my $distname = $mcpan->module( $modname )->{distribution};
596             if (${$dep}{phase} eq q{runtime}) {
597                 if (${$dep}{relationship} eq q{requires}) {
598                     $runtime{$distname} = 1;
599                 }
600                 else {
601                     $optional{$distname} = 1 if $recommend && $top;
602                 }
603             }
604             else { # configure, build
605                 $build{$distname} = 1;
606             }
607         }
608         $deps_build{$name} = [keys %build];
609         $deps_runtime{$name} = [keys %runtime];
610         $deps_optional{$name} = [keys %optional];
611         foreach my $distname (@{$deps_build{$name}}) {
612             fetch( $distname, 0, 1 );
613         }
614         foreach my $distname (@{$deps_runtime{$name}}) {
615             fetch( $distname, $need_target, $need_host );
616             $need_dlopen{$name} ||= $need_dlopen{$distname};
617         }
618         foreach my $distname (@{$deps_optional{$name}}) {
619             fetch( $distname, $need_target, $need_host );
620         }
621     }
622     return;
623 }
624
625 foreach my $distname (@ARGV) {
626     # Command-line's distributions
627     fetch( $distname, !!$target, !!$host, 1 );
628 }
629 say scalar keys %dist, q{ packages fetched.} unless $quiet;
630
631 # Buildroot package name: lowercase
632 sub fsname {
633     my $name = shift;
634     $name =~ s|_|-|g;
635     return q{perl-} . lc $name;
636 }
637
638 # Buildroot variable name: uppercase
639 sub brname {
640     my $name = shift;
641     $name =~ s|-|_|g;
642     return uc $name;
643 }
644
645 while (my ($distname, $dist) = each %dist) {
646     my $fsname = fsname( $distname );
647     my $dirname = q{package/} . $fsname;
648     my $cfgname = $dirname . q{/Config.in};
649     my $mkname = $dirname . q{/} . $fsname . q{.mk};
650     my $hashname = $dirname . q{/} . $fsname . q{.hash};
651     my $brname = brname( $fsname );
652     mkdir $dirname unless -d $dirname;
653     if ($need_target{$distname} && ($force || !-f $cfgname)) {
654         my $abstract = $dist->{abstract};
655         my $homepage = $dist->{resources}->{homepage} || qq{https://metacpan.org/release/${distname}};
656         say qq{write ${cfgname}} unless $quiet;
657         open my $fh, q{>}, $cfgname;
658         say {$fh} qq{config BR2_PACKAGE_${brname}};
659         say {$fh} qq{\tbool "${fsname}"};
660         say {$fh} qq{\tdepends on !BR2_STATIC_LIBS} if $need_dlopen{$distname};
661         foreach my $dep (sort @{$deps_runtime{$distname}}) {
662             my $brdep = brname( fsname( $dep ) );
663             say {$fh} qq{\tselect BR2_PACKAGE_${brdep}};
664         }
665         say {$fh} qq{\thelp};
666         say {$fh} qq{\t  ${abstract}\n} if $abstract;
667         say {$fh} qq{\t  ${homepage}};
668         if ($need_dlopen{$distname}) {
669             say {$fh} qq{\ncomment "${fsname} needs a toolchain w/ dynamic library"};
670             say {$fh} qq{\tdepends on BR2_STATIC_LIBS};
671         }
672         close $fh;
673     }
674     if ($force || !-f $mkname) {
675         my $version = $dist->{version};
676         my ($path) = $dist->{download_url} =~ m|^[^:/?#]+://[^/?#]*([^?#]*)|;
677         # this URL contains only the scheme, auth and path parts (but no query and fragment parts)
678         # the scheme is not used, because the job is done by the BR download infrastructure
679         # the auth part is not used, because we use $(BR2_CPAN_MIRROR)
680         my ($filename, $directories, $suffix) = fileparse( $path, q{tar.gz}, q{tgz} );
681         $directories =~ s|/$||;
682         my $dependencies = join q{ }, map( { q{host-} . fsname( $_ ); } sort @{$deps_build{$distname}} ),
683                                       map( { fsname( $_ ); } sort @{$deps_runtime{$distname}} );
684         my $host_dependencies = join q{ }, map { q{host-} . fsname( $_ ); } sort( @{$deps_build{$distname}},
685                                                                                   @{$deps_runtime{$distname}} );
686         my $license = ref $dist->{license} eq 'ARRAY'
687                     ? join q{ or }, @{$dist->{license}}
688                     : $dist->{license};
689         # BR requires license name as in http://spdx.org/licenses/
690         $license =~ s|apache_2_0|Apache-2.0|;
691         $license =~ s|artistic_2|Artistic-2.0|;
692         $license =~ s|mit|MIT|;
693         $license =~ s|openssl|OpenSSL|;
694         $license =~ s|perl_5|Artistic or GPL-1.0+|;
695         my $license_files = join q{ }, @{$license_files{$distname}};
696         say qq{write ${mkname}} unless $quiet;
697         open my $fh, q{>}, $mkname;
698         say {$fh} qq{################################################################################};
699         say {$fh} qq{#};
700         say {$fh} qq{# ${fsname}};
701         say {$fh} qq{#};
702         say {$fh} qq{################################################################################};
703         say {$fh} qq{};
704         say {$fh} qq{${brname}_VERSION = ${version}};
705         say {$fh} qq{${brname}_SOURCE = ${distname}-\$(${brname}_VERSION).${suffix}};
706         say {$fh} qq{${brname}_SITE = \$(BR2_CPAN_MIRROR)${directories}};
707         say {$fh} qq{${brname}_DEPENDENCIES = ${dependencies}} if $need_target{$distname} && $dependencies;
708         say {$fh} qq{HOST_${brname}_DEPENDENCIES = ${host_dependencies}} if $need_host{$distname} && $host_dependencies;
709         say {$fh} qq{${brname}_LICENSE = ${license}} if $license && $license ne q{unknown};
710         say {$fh} qq{${brname}_LICENSE_FILES = ${license_files}} if $license_files;
711         say {$fh} qq{};
712         foreach (sort @{$deps_optional{$distname}}) {
713             next if grep { $_ eq $distname; } @{$deps_runtime{$_}};     # avoid cyclic dependencies
714             my $opt_brname = brname( $_ );
715             my $opt_fsname = fsname( $_ );
716             say {$fh} qq{ifeq (\$(BR2_PACKAGE_PERL_${opt_brname}),y)};
717             say {$fh} qq{${brname}_DEPENDENCIES += ${opt_fsname}};
718             say {$fh} qq{endif};
719             say {$fh} qq{};
720         }
721         say {$fh} qq{\$(eval \$(perl-package))} if $need_target{$distname};
722         say {$fh} qq{\$(eval \$(host-perl-package))} if $need_host{$distname};
723         close $fh;
724     }
725     if ($force || !-f $hashname) {
726         my ($checksum, $filename) = get_checksum($dist->{download_url});
727         my $md5 = $checksum->{md5};
728         my $sha256 = $checksum->{sha256};
729         say qq{write ${hashname}} unless $quiet;
730         open my $fh, q{>}, $hashname;
731         say {$fh} qq{# retrieved by scancpan from ${mirror}/};
732         say {$fh} qq{md5    ${md5} ${filename}};
733         say {$fh} qq{sha256 ${sha256} ${filename}};
734         close $fh;
735     }
736 }
737
738 my %pkg;
739 my $cfgname = q{package/Config.in};
740 if (-f $cfgname) {
741     open my $fh, q{<}, $cfgname;
742     while (<$fh>) {
743         chomp;
744         $pkg{$_} = 1 if m|package/perl-|;
745     }
746     close $fh;
747 }
748
749 foreach my $distname (keys %need_target) {
750     my $fsname = fsname( $distname );
751     $pkg{qq{\tsource "package/${fsname}/Config.in"}} = 1;
752 }
753
754 say qq{${cfgname} must contain the following lines:};
755 say join qq{\n}, sort keys %pkg;
756
757 __END__
758
759 =head1 NAME
760
761 utils/scancpan Try-Tiny Moo
762
763 =head1 SYNOPSIS
764
765 supports/scripts/scancpan [options] [distname ...]
766
767  Options:
768    -help
769    -man
770    -quiet
771    -force
772    -target/-notarget
773    -host/-nohost
774    -recommend
775    -test
776
777 =head1 OPTIONS
778
779 =over 8
780
781 =item B<-help>
782
783 Prints a brief help message and exits.
784
785 =item B<-man>
786
787 Prints the manual page and exits.
788
789 =item B<-quiet>
790
791 Executes without output
792
793 =item B<-force>
794
795 Forces the overwriting of existing files.
796
797 =item B<-target/-notarget>
798
799 Switches package generation for the target variant (the default is C<-target>).
800
801 =item B<-host/-nohost>
802
803 Switches package generation for the host variant (the default is C<-nohost>).
804
805 =item B<-recommend>
806
807 Adds I<recommended> dependencies.
808
809 =item B<-test>
810
811 Adds dependencies for test.
812
813 =back
814
815 =head1 DESCRIPTION
816
817 This script creates templates of the Buildroot package files for all the
818 Perl/CPAN distributions required by the specified distnames. The
819 dependencies and metadata are fetched from https://metacpan.org/.
820
821 After running this script, it is necessary to check the generated files.
822 You have to manually add the license files (PERL_FOO_LICENSE_FILES variable).
823 For distributions that link against a target library, you have to add the
824 buildroot package name for that library to the DEPENDENCIES variable.
825
826 See the Buildroot documentation for details on the usage of the Perl
827 infrastructure.
828
829 The major version of the host perl must be aligned on the target one,
830 in order to work with the right CoreList data.
831
832 =head1 LICENSE
833
834 Copyright (C) 2013-2017 by Francois Perrad <francois.perrad@gadz.org>
835
836 This program is free software; you can redistribute it and/or modify
837 it under the terms of the GNU General Public License as published by
838 the Free Software Foundation; either version 2 of the License, or
839 (at your option) any later version.
840
841 This program is distributed in the hope that it will be useful,
842 but WITHOUT ANY WARRANTY; without even the implied warranty of
843 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
844 General Public License for more details.
845
846 You should have received a copy of the GNU General Public License
847 along with this program; if not, write to the Free Software
848 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
849
850 This script is a part of Buildroot.
851
852 This script requires the module C<MetaCPAN::API::Tiny> (version 1.131730)
853 which was included at the beginning of this file by the tool C<fatpack>.
854
855 See L<http://search.cpan.org/~nperez/MetaCPAN-API-Tiny-1.131730/>.
856
857 See L<http://search.cpan.org/search?query=App-FatPacker&mode=dist>.
858
859 These both libraries are free software and may be distributed under the same
860 terms as perl itself.
861
862 And perl may be distributed under the terms of Artistic v1 or GPL v1 license.
863
864 =cut