Showing 3 changed files with 611 additions and 12181 deletions
+9 -29
cpanfile
... ...
@@ -1,36 +1,16 @@
1
-requires 'DBI', '== 1.625';
2
-requires 'DBD::SQLite', '== 1.40';
3
-requires 'Object::Simple', '== 3.09';
4
-requires 'DBIx::Custom', '== 0.28';
5
-requires 'Config::Tiny', '== 2.14';
6
-requires 'Time::HiRes', '== 1.9725';
7
-requires 'Test::Simple', '== 0.98';
8
-requires 'Validator::Custom', '== 1.01';
1
+requires 'Time::HiRes', '== 1.9732';
2
+requires 'DBD::SQLite', '== 1.50';
3
+requires 'DBI', '== 1.634';
9 4
 requires 'DBIx::Connector', '== 0.53';
10
-requires 'Module::Build', '== 0.4003';
11
-requires 'Test::Harness', '== 3.26';
12
-requires 'Module::Metadata', '== 1.000011';
13
-requires 'Perl::OSType', '== 1.003';
14
-requires 'ExtUtils::CBuilder', '== 0.280205';
15
-requires 'File::Spec', '== 3.40';
16
-requires 'IPC::Cmd', '== 0.80';
17
-requires 'Locale::Maketext::Simple', '== 0.21';
18
-requires 'Module::Load::Conditional', '== 0.54';
19
-requires 'Module::Load', '== 0.24';
20
-requires 'Params::Check', '== 0.36';
21
-requires 'ExtUtils::ParseXS', '== 3.24';
22
-requires 'Test::MockModule', '== 0.05';
23
-requires 'Digest::SHA', '== 5.84';
24
-requires 'Text::Markdown::Hoedown', '== 1.01';
25
-requires 'parent', '== 0.228';
5
+requires 'Object::Simple', '== 3.14';
6
+requires 'DBIx::Custom', '== 0.36';
7
+requires 'Validator::Custom', '== 1.01';
8
+requires 'Config::Tiny', '== 2.23';
26 9
 requires 'Data::Page', '== 2.02';
27
-requires 'Class::Accessor::Chained', '== 0.01';
28
-requires 'Class::Accessor', '== 0.34';
29
-requires 'Test::Exception', '== 0.32';
30
-requires 'Sub::Uplevel', '== 0.24';
31
-requires 'Data::Page::Navigation', '== 0.06';
32 10
 requires 'Data::Page::Navigation', '== 0.06';
11
+requires 'Mojolicious', '== 6.57';
33 12
 requires 'Mojolicious::Plugin::BasicAuth', '== 0.08';
34 13
 requires 'Mojolicious::Plugin::AutoRoute', '== 0.19';
35 14
 requires 'Mojolicious::Plugin::INIConfig', '== 0.03';
36 15
 requires 'Mojolicious::Plugin::DBViewer', '== 0.28';
16
+requires 'Text::Markdown::Hoedown', '== 1.01';
+600 -12150
cpanm 1000644 → 1000755
... ...
@@ -1,481 +1,35 @@
1 1
 #!/usr/bin/env perl
2 2
 #
3
-# You want to install cpanminus? Run the following command and it will
4
-# install itself for you. You might want to run it as a root with sudo
5
-# if you want to install to places like /usr/local/bin.
3
+# This is a pre-compiled source code for the cpanm (cpanminus) program.
4
+# For more details about how to install cpanm, go to the following URL:
6 5
 #
7
-#   % curl -L http://cpanmin.us | perl - --self-upgrade
6
+#   https://github.com/miyagawa/cpanminus
8 7
 #
9
-# If you don't have curl but wget, replace `curl -L` with `wget -O -`.
8
+# Quickstart: Run the following command and it will install itself for
9
+# you. You might want to run it as a root with sudo if you want to install
10
+# to places like /usr/local/bin.
10 11
 #
11
-# For more details about this program, visit http://search.cpan.org/dist/App-cpanminus
12
+#   % curl -L https://cpanmin.us | perl - App::cpanminus
12 13
 #
14
+# If you don't have curl but wget, replace `curl -L` with `wget -O -`.
15
+
13 16
 # DO NOT EDIT -- this is an auto generated file
17
+
14 18
 # This chunk of stuff was generated by App::FatPacker. To find the original
15 19
 # file's code, look for the end of this BEGIN block or the string 'FATPACK'
16 20
 BEGIN {
17 21
 my %fatpacked;
18 22
 
19
-$fatpacked{"App/cpanminus.pm"} = <<'APP_CPANMINUS';
20
-  package App::cpanminus;
21
-  our $VERSION = "1.6005";
22
-  
23
-  =head1 NAME
24
-  
25
-  App::cpanminus - get, unpack, build and install modules from CPAN
26
-  
27
-  =head1 SYNOPSIS
28
-  
29
-      cpanm Module
30
-  
31
-  Run C<cpanm -h> or C<perldoc cpanm> for more options.
32
-  
33
-  =head1 DESCRIPTION
34
-  
35
-  cpanminus is a script to get, unpack, build and install modules from
36
-  CPAN and does nothing else.
37
-  
38
-  It's dependency free (can bootstrap itself), requires zero
39
-  configuration, and stands alone. When running, it requires only 10MB
40
-  of RAM.
41
-  
42
-  =head1 INSTALLATION
43
-  
44
-  There are several ways to install cpanminus to your system.
45
-  
46
-  =head2 Package management system
47
-  
48
-  There are Debian packages, RPMs, FreeBSD ports, and packages for other
49
-  operation systems available. If you want to use the package management system,
50
-  search for cpanminus and use the appropriate command to install. This makes it
51
-  easy to install C<cpanm> to your system without thinking about where to
52
-  install, and later upgrade.
53
-  
54
-  =head2 Installing to system perl
55
-  
56
-  You can also use the latest cpanminus to install cpanminus itself:
57
-  
58
-      curl -L http://cpanmin.us | perl - --sudo App::cpanminus
59
-  
60
-  This will install C<cpanm> to your bin directory like
61
-  C</usr/local/bin> (unless you configured C<INSTALL_BASE> with
62
-  L<local::lib>), so you probably need the C<--sudo> option.
63
-  
64
-  =head2 Installing to local perl (perlbrew)
65
-  
66
-  If you have perl in your home directory, which is the case if you use
67
-  tools like L<perlbrew>, you don't need the C<--sudo> option, since
68
-  you're most likely to have a write permission to the perl's library
69
-  path. You can just do:
70
-  
71
-      curl -L http://cpanmin.us | perl - App::cpanminus
72
-  
73
-  to install the C<cpanm> executable to the perl's bin path, like
74
-  C<~/perl5/perlbrew/bin/cpanm>.
75
-  
76
-  =head2 Downloading the standalone executable
77
-  
78
-  You can also copy the standalone executable to whatever location you'd like.
79
-  
80
-      cd ~/bin
81
-      curl -LO http://xrl.us/cpanm
82
-      chmod +x cpanm
83
-      # edit shebang if you don't have /usr/bin/env
84
-  
85
-  This just works, but be sure to grab the new version manually when you
86
-  upgrade because C<--self-upgrade> might not work for this.
87
-  
88
-  =head1 DEPENDENCIES
89
-  
90
-  perl 5.8 or later.
91
-  
92
-  =over 4
93
-  
94
-  =item *
95
-  
96
-  'tar' executable (bsdtar or GNU tar version 1.22 are rcommended) or Archive::Tar to unpack files.
97
-  
98
-  =item *
99
-  
100
-  C compiler, if you want to build XS modules.
101
-  
102
-  =item *
103
-  
104
-  make
105
-  
106
-  =item *
107
-  
108
-  Module::Build (core in 5.10)
109
-  
110
-  =back
111
-  
112
-  =head1 QUESTIONS
113
-  
114
-  =head2 Another CPAN installer?
115
-  
116
-  OK, the first motivation was this: the CPAN shell runs out of memory (or swaps
117
-  heavily and gets really slow) on Slicehost/linode's most affordable plan with
118
-  only 256MB RAM. Should I pay more to install perl modules from CPAN? I don't
119
-  think so.
120
-  
121
-  =head2 But why a new client?
122
-  
123
-  First of all, let me be clear that CPAN and CPANPLUS are great tools
124
-  I've used for I<literally> years (you know how many modules I have on
125
-  CPAN, right?). I really respect their efforts of maintaining the most
126
-  important tools in the CPAN toolchain ecosystem.
127
-  
128
-  However, for less experienced users (mostly from outside the Perl community),
129
-  or even really experienced Perl developers who know how to shoot themselves in
130
-  their feet, setting up the CPAN toolchain often feels like yak shaving,
131
-  especially when all they want to do is just install some modules and start
132
-  writing code.
133
-  
134
-  =head2 Zero-conf? How does this module get/parse/update the CPAN index?
135
-  
136
-  It queries the CPAN Meta DB site at L<http://cpanmetadb.plackperl.org/>.
137
-  The site is updated at least every hour to reflect the latest changes
138
-  from fast syncing mirrors. The script then also falls back to query the
139
-  module at L<http://metacpan.org/> using its wonderful API.
140
-  
141
-  Fetched files are unpacked in C<~/.cpanm> and automatically cleaned up
142
-  periodically.  You can configure the location of this with the
143
-  C<PERL_CPANM_HOME> environment variable.
144
-  
145
-  =head2 Where does this install modules to? Do I need root access?
146
-  
147
-  It installs to wherever ExtUtils::MakeMaker and Module::Build are
148
-  configured to (via C<PERL_MM_OPT> and C<PERL_MB_OPT>). So if you're
149
-  using local::lib, then it installs to your local perl5
150
-  directory. Otherwise it installs to the site_perl directory that
151
-  belongs to your perl.
152
-  
153
-  cpanminus at a boot time checks whether you have configured
154
-  local::lib, or have the permission to install modules to the site_perl
155
-  directory.  If neither, it automatically sets up local::lib compatible
156
-  installation path in a C<perl5> directory under your home
157
-  directory. To avoid this, run the script as the root user, with
158
-  C<--sudo> option or with C<--local-lib> option.
159
-  
160
-  =head2 cpanminus can't install the module XYZ. Is it a bug?
161
-  
162
-  It is more likely a problem with the distribution itself. cpanminus
163
-  doesn't support or is known to have issues with distributions like as
164
-  follows:
165
-  
166
-  =over 4
167
-  
168
-  =item *
169
-  
170
-  Tests that require input from STDIN.
171
-  
172
-  =item *
173
-  
174
-  Tests that might fail when C<AUTOMATED_TESTING> is enabled.
175
-  
176
-  =item *
177
-  
178
-  Modules that have invalid numeric values as VERSION (such as C<1.1a>)
179
-  
180
-  =back
181
-  
182
-  These failures can be reported back to the author of the module so
183
-  that they can fix it accordingly, rather than me.
184
-  
185
-  =head2 Does cpanm support the feature XYZ of L<CPAN> and L<CPANPLUS>?
186
-  
187
-  Most likely not. Here are the things that cpanm doesn't do by
188
-  itself. And it's a feature - you got that from the name I<minus>,
189
-  right?
190
-  
191
-  If you need these features, use L<CPAN>, L<CPANPLUS> or the standalone
192
-  tools that are mentioned.
193
-  
194
-  =over 4
195
-  
196
-  =item *
197
-  
198
-  Bundle:: module dependencies
199
-  
200
-  =item *
201
-  
202
-  CPAN testers reporting
203
-  
204
-  =item *
205
-  
206
-  Building RPM packages from CPAN modules
207
-  
208
-  =item *
209
-  
210
-  Listing the outdated modules that needs upgrading. See L<App::cpanoutdated>
211
-  
212
-  =item *
213
-  
214
-  Uninstalling modules. See L<pm-uninstall>.
215
-  
216
-  =item *
217
-  
218
-  Showing the changes of the modules you're about to upgrade. See L<cpan-listchanges>
219
-  
220
-  =item *
221
-  
222
-  Patching CPAN modules with distroprefs.
223
-  
224
-  =back
225
-  
226
-  See L<cpanm> or C<cpanm -h> to see what cpanminus I<can> do :)
227
-  
228
-  =head1 COPYRIGHT
229
-  
230
-  Copyright 2010- Tatsuhiko Miyagawa
231
-  
232
-  The standalone executable contains the following modules embedded.
233
-  
234
-  =over 4
235
-  
236
-  =item L<CPAN::DistnameInfo> Copyright 2003 Graham Barr
237
-  
238
-  =item L<Parse::CPAN::Meta> Copyright 2006-2009 Adam Kennedy
239
-  
240
-  =item L<local::lib> Copyright 2007-2009 Matt S Trout
241
-  
242
-  =item L<HTTP::Tiny> Copyright 2011 Christian Hansen
243
-  
244
-  =item L<Module::Metadata> Copyright 2001-2006 Ken Williams. 2010 Matt S Trout
245
-  
246
-  =item L<version> Copyright 2004-2010 John Peacock
247
-  
248
-  =item L<JSON::PP> Copyright 2007−2011 by Makamaka Hannyaharamitu
249
-  
250
-  =item L<CPAN::Meta>, L<CPAN::Meta::Requirements> Copyright (c) 2010 by David Golden and Ricardo Signes
251
-  
252
-  =item L<CPAN::Meta::YAML> Copyright 2010 Adam Kennedy
253
-  
254
-  =item L<File::pushd> Copyright 2012 David Golden
255
-  
256
-  =back
257
-  
258
-  =head1 LICENSE
259
-  
260
-  Same as Perl.
261
-  
262
-  =head1 CREDITS
263
-  
264
-  =head2 CONTRIBUTORS
265
-  
266
-  Patches and code improvements were contributed by:
267
-  
268
-  Goro Fuji, Kazuhiro Osawa, Tokuhiro Matsuno, Kenichi Ishigaki, Ian
269
-  Wells, Pedro Melo, Masayoshi Sekimura, Matt S Trout (mst), squeeky,
270
-  horus and Ingy dot Net.
271
-  
272
-  =head2 ACKNOWLEDGEMENTS
273
-  
274
-  Bug reports, suggestions and feedbacks were sent by, or general
275
-  acknowledgement goes to:
276
-  
277
-  Jesse Vincent, David Golden, Andreas Koenig, Jos Boumans, Chris
278
-  Williams, Adam Kennedy, Audrey Tang, J. Shirley, Chris Prather, Jesse
279
-  Luehrs, Marcus Ramberg, Shawn M Moore, chocolateboy, Chirs Nehren,
280
-  Jonathan Rockway, Leon Brocard, Simon Elliott, Ricardo Signes, AEvar
281
-  Arnfjord Bjarmason, Eric Wilhelm, Florian Ragwitz and xaicron.
282
-  
283
-  =head1 COMMUNITY
284
-  
285
-  =over 4
286
-  
287
-  =item L<http://github.com/miyagawa/cpanminus> - source code repository, issue tracker
288
-  
289
-  =item L<irc://irc.perl.org/#toolchain> - discussions about Perl toolchain. I'm there.
290
-  
291
-  =back
292
-  
293
-  =head1 NO WARRANTY
294
-  
295
-  This software is provided "as-is," without any express or implied
296
-  warranty. In no event shall the author be held liable for any damages
297
-  arising from the use of the software.
298
-  
299
-  =head1 SEE ALSO
300
-  
301
-  L<CPAN> L<CPANPLUS> L<pip>
302
-  
303
-  =cut
304
-  
305
-  1;
23
+$fatpacked{"App/cpanminus.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'APP_CPANMINUS';
24
+  package App::cpanminus;our$VERSION="1.7040";1;
306 25
 APP_CPANMINUS
307 26
 
308
-$fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
309
-  package App::cpanminus::script;
310
-  use strict;
311
-  use Config;
312
-  use Cwd ();
313
-  use App::cpanminus;
314
-  use File::Basename ();
315
-  use File::Find ();
316
-  use File::Path ();
317
-  use File::Spec ();
318
-  use File::Copy ();
319
-  use File::Temp ();
320
-  use Getopt::Long ();
321
-  use Parse::CPAN::Meta;
322
-  use Symbol ();
323
-  
324
-  use constant WIN32 => $^O eq 'MSWin32';
325
-  use constant SUNOS => $^O eq 'solaris';
326
-  
327
-  our $VERSION = $App::cpanminus::VERSION;
328
-  
329
-  if ($INC{"App/FatPacker/Trace.pm"}) {
330
-      require JSON::PP;
331
-      require CPAN::Meta::YAML;
332
-      require CPAN::Meta::Prereqs;
333
-      require version::vpp;
334
-      require File::pushd;
335
-  }
336
-  
337
-  my $quote = WIN32 ? q/"/ : q/'/;
338
-  
339
-  sub agent {
340
-      my $self = shift;
341
-      "cpanminus/$VERSION perl/$]";
342
-  }
343
-  
344
-  sub determine_home {
345
-      my $class = shift;
346
-  
347
-      my $homedir = $ENV{HOME}
348
-        || eval { require File::HomeDir; File::HomeDir->my_home }
349
-        || join('', @ENV{qw(HOMEDRIVE HOMEPATH)}); # Win32
350
-  
351
-      if (WIN32) {
352
-          require Win32; # no fatpack
353
-          $homedir = Win32::GetShortPathName($homedir);
354
-      }
355
-  
356
-      return "$homedir/.cpanm";
357
-  }
358
-  
359
-  sub new {
360
-      my $class = shift;
361
-  
362
-      bless {
363
-          home => $class->determine_home,
364
-          cmd  => 'install',
365
-          seen => {},
366
-          notest => undef,
367
-          test_only => undef,
368
-          installdeps => undef,
369
-          force => undef,
370
-          sudo => undef,
371
-          make  => undef,
372
-          verbose => undef,
373
-          quiet => undef,
374
-          interactive => undef,
375
-          log => undef,
376
-          mirrors => [],
377
-          mirror_only => undef,
378
-          mirror_index => undef,
379
-          perl => $^X,
380
-          argv => [],
381
-          local_lib => undef,
382
-          self_contained => undef,
383
-          prompt_timeout => 0,
384
-          prompt => undef,
385
-          configure_timeout => 60,
386
-          try_lwp => 1,
387
-          try_wget => 1,
388
-          try_curl => 1,
389
-          uninstall_shadows => ($] < 5.012),
390
-          skip_installed => 1,
391
-          skip_satisfied => 0,
392
-          auto_cleanup => 7, # days
393
-          pod2man => 1,
394
-          installed_dists => 0,
395
-          showdeps => 0,
396
-          scandeps => 0,
397
-          scandeps_tree => [],
398
-          format   => 'tree',
399
-          save_dists => undef,
400
-          skip_configure => 0,
401
-          verify => 0,
402
-          @_,
403
-      }, $class;
404
-  }
405
-  
406
-  sub env {
407
-      my($self, $key) = @_;
408
-      $ENV{"PERL_CPANM_" . $key};
409
-  }
410
-  
411
-  sub parse_options {
412
-      my $self = shift;
413
-  
414
-      local @ARGV = @{$self->{argv}};
415
-      push @ARGV, split /\s+/, $self->env('OPT');
416
-      push @ARGV, @_;
417
-  
418
-      Getopt::Long::Configure("bundling");
419
-      Getopt::Long::GetOptions(
420
-          'f|force'   => sub { $self->{skip_installed} = 0; $self->{force} = 1 },
421
-          'n|notest!' => \$self->{notest},
422
-          'test-only' => sub { $self->{notest} = 0; $self->{skip_installed} = 0; $self->{test_only} = 1 },
423
-          'S|sudo!'   => \$self->{sudo},
424
-          'v|verbose' => sub { $self->{verbose} = $self->{interactive} = 1 },
425
-          'verify!'   => \$self->{verify},
426
-          'q|quiet!'  => \$self->{quiet},
427
-          'h|help'    => sub { $self->{action} = 'show_help' },
428
-          'V|version' => sub { $self->{action} = 'show_version' },
429
-          'perl=s'    => \$self->{perl},
430
-          'l|local-lib=s' => sub { $self->{local_lib} = $self->maybe_abs($_[1]) },
431
-          'L|local-lib-contained=s' => sub {
432
-              $self->{local_lib} = $self->maybe_abs($_[1]);
433
-              $self->{self_contained} = 1;
434
-              $self->{pod2man} = undef;
435
-          },
436
-          'mirror=s@' => $self->{mirrors},
437
-          'mirror-only!' => \$self->{mirror_only},
438
-          'mirror-index=s'  => \$self->{mirror_index},
439
-          'cascade-search!' => \$self->{cascade_search},
440
-          'prompt!'   => \$self->{prompt},
441
-          'installdeps' => \$self->{installdeps},
442
-          'skip-installed!' => \$self->{skip_installed},
443
-          'skip-satisfied!' => \$self->{skip_satisfied},
444
-          'reinstall'    => sub { $self->{skip_installed} = 0 },
445
-          'interactive!' => \$self->{interactive},
446
-          'i|install' => sub { $self->{cmd} = 'install' },
447
-          'info'      => sub { $self->{cmd} = 'info' },
448
-          'look'      => sub { $self->{cmd} = 'look'; $self->{skip_installed} = 0 },
449
-          'self-upgrade' => sub { $self->check_upgrade; $self->{cmd} = 'install'; $self->{skip_installed} = 1; push @ARGV, 'App::cpanminus' },
450
-          'uninst-shadows!'  => \$self->{uninstall_shadows},
451
-          'lwp!'    => \$self->{try_lwp},
452
-          'wget!'   => \$self->{try_wget},
453
-          'curl!'   => \$self->{try_curl},
454
-          'auto-cleanup=s' => \$self->{auto_cleanup},
455
-          'man-pages!' => \$self->{pod2man},
456
-          'scandeps'   => \$self->{scandeps},
457
-          'showdeps'   => sub { $self->{showdeps} = 1; $self->{skip_installed} = 0 },
458
-          'format=s'   => \$self->{format},
459
-          'save-dists=s' => sub {
460
-              $self->{save_dists} = $self->maybe_abs($_[1]);
461
-          },
462
-          'skip-configure!' => \$self->{skip_configure},
463
-          'dev!'       => \$self->{dev_release},
464
-          'metacpan!'  => \$self->{metacpan},
465
-      );
466
-  
467
-      if (!@ARGV && $0 ne '-' && !-t STDIN){ # e.g. # cpanm < author/requires.cpanm
468
-          push @ARGV, $self->load_argv_from_fh(\*STDIN);
469
-          $self->{load_from_stdin} = 1;
470
-      }
471
-  
472
-      $self->{argv} = \@ARGV;
473
-  }
474
-  
475
-  sub check_upgrade {
476
-      if ($0 !~ /^$Config{installsitebin}/) {
477
-          if ($0 =~ m!perlbrew/bin!) {
478
-              warn <<WARN;
27
+$fatpacked{"App/cpanminus/Dependency.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'APP_CPANMINUS_DEPENDENCY';
28
+  package App::cpanminus::Dependency;use strict;use CPAN::Meta::Requirements;sub from_prereqs {my($class,$prereqs,$phases,$types)=@_;my@deps;for my$type (@$types){push@deps,$class->from_versions($prereqs->merged_requirements($phases,[$type])->as_string_hash,$type,)}return@deps}sub from_versions {my($class,$versions,$type)=@_;my@deps;while (my($module,$version)=each %$versions){push@deps,$class->new($module,$version,$type)}@deps}sub merge_with {my($self,$requirements)=@_;$self->{original_version}=$self->version;eval {$requirements->add_string_requirement($self->module,$self->version)};if ($@ =~ /illegal requirements/){warn sprintf("Can't merge requirements for %s: '%s' and '%s'",$self->module,$self->version,$requirements->requirements_for_module($self->module))}$self->{version}=$requirements->requirements_for_module($self->module)}sub new {my($class,$module,$version,$type)=@_;bless {module=>$module,version=>$version,type=>$type || 'requires',},$class}sub module {$_[0]->{module}}sub version {$_[0]->{version}}sub type {$_[0]->{type}}sub requires_version {my$self=shift;if (defined$self->{original_version}){return$self->{original_version}}$self->version}sub is_requirement {$_[0]->{type}eq 'requires'}1;
29
+APP_CPANMINUS_DEPENDENCY
30
+
31
+$fatpacked{"App/cpanminus/script.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'APP_CPANMINUS_SCRIPT';
32
+  package App::cpanminus::script;use strict;use Config;use Cwd ();use App::cpanminus;use App::cpanminus::Dependency;use File::Basename ();use File::Find ();use File::Path ();use File::Spec ();use File::Copy ();use File::Temp ();use Getopt::Long ();use Symbol ();use String::ShellQuote ();use version ();use constant WIN32=>$^O eq 'MSWin32';use constant BAD_TAR=>($^O eq 'solaris' || $^O eq 'hpux');use constant CAN_SYMLINK=>eval {symlink("","");1};our$VERSION=$App::cpanminus::VERSION;if ($INC{"App/FatPacker/Trace.pm"}){require version::vpp}my$quote=WIN32 ? q/"/ : q/'/;sub agent {my$self=shift;my$agent="cpanminus/$VERSION";$agent .= " perl/$]" if$self->{report_perl_version};$agent}sub determine_home {my$class=shift;my$homedir=$ENV{HOME}|| eval {require File::HomeDir;File::HomeDir->my_home}|| join('',@ENV{qw(HOMEDRIVE HOMEPATH)});if (WIN32){require Win32;$homedir=Win32::GetShortPathName($homedir)}return "$homedir/.cpanm"}sub new {my$class=shift;bless {home=>$class->determine_home,cmd=>'install',seen=>{},notest=>undef,test_only=>undef,installdeps=>undef,force=>undef,sudo=>undef,make=>undef,verbose=>undef,quiet=>undef,interactive=>undef,log=>undef,mirrors=>[],mirror_only=>undef,mirror_index=>undef,cpanmetadb=>"http://cpanmetadb.plackperl.org/v1.0/",perl=>$^X,argv=>[],local_lib=>undef,self_contained=>undef,exclude_vendor=>undef,prompt_timeout=>0,prompt=>undef,configure_timeout=>60,build_timeout=>3600,test_timeout=>1800,try_lwp=>1,try_wget=>1,try_curl=>1,uninstall_shadows=>($] < 5.012),skip_installed=>1,skip_satisfied=>0,auto_cleanup=>7,pod2man=>1,installed_dists=>0,install_types=>['requires'],with_develop=>0,showdeps=>0,scandeps=>0,scandeps_tree=>[],format=>'tree',save_dists=>undef,skip_configure=>0,verify=>0,report_perl_version=>!$class->maybe_ci,build_args=>{},features=>{},pure_perl=>0,cpanfile_path=>'cpanfile',@_,},$class}sub env {my($self,$key)=@_;$ENV{"PERL_CPANM_" .$key}}sub maybe_ci {my$class=shift;grep$ENV{$_},qw(TRAVIS CI AUTOMATED_TESTING AUTHOR_TESTING)}sub install_type_handlers {my$self=shift;my@handlers;for my$type (qw(recommends suggests)){push@handlers,"with-$type"=>sub {my%uniq;$self->{install_types}=[grep!$uniq{$_}++,@{$self->{install_types}},$type ]};push@handlers,"without-$type"=>sub {$self->{install_types}=[grep $_ ne $type,@{$self->{install_types}}]}}@handlers}sub build_args_handlers {my$self=shift;my@handlers;for my$phase (qw(configure build test install)){push@handlers,"$phase-args=s"=>\($self->{build_args}{$phase})}@handlers}sub parse_options {my$self=shift;local@ARGV=@{$self->{argv}};push@ARGV,grep length,split /\s+/,$self->env('OPT');push@ARGV,@_;Getopt::Long::Configure("bundling");Getopt::Long::GetOptions('f|force'=>sub {$self->{skip_installed}=0;$self->{force}=1},'n|notest!'=>\$self->{notest},'test-only'=>sub {$self->{notest}=0;$self->{skip_installed}=0;$self->{test_only}=1},'S|sudo!'=>\$self->{sudo},'v|verbose'=>\$self->{verbose},'verify!'=>\$self->{verify},'q|quiet!'=>\$self->{quiet},'h|help'=>sub {$self->{action}='show_help'},'V|version'=>sub {$self->{action}='show_version'},'perl=s'=>sub {$self->diag("--perl is deprecated since it's known to be fragile in figuring out dependencies. Run `$_[1] -S cpanm` instead.\n",1);$self->{perl}=$_[1]},'l|local-lib=s'=>sub {$self->{local_lib}=$self->maybe_abs($_[1])},'L|local-lib-contained=s'=>sub {$self->{local_lib}=$self->maybe_abs($_[1]);$self->{self_contained}=1;$self->{pod2man}=undef},'self-contained!'=>\$self->{self_contained},'exclude-vendor!'=>\$self->{exclude_vendor},'mirror=s@'=>$self->{mirrors},'mirror-only!'=>\$self->{mirror_only},'mirror-index=s'=>sub {$self->{mirror_index}=$self->maybe_abs($_[1])},'M|from=s'=>sub {$self->{mirrors}=[$_[1]];$self->{mirror_only}=1},'cpanmetadb=s'=>\$self->{cpanmetadb},'cascade-search!'=>\$self->{cascade_search},'prompt!'=>\$self->{prompt},'installdeps'=>\$self->{installdeps},'skip-installed!'=>\$self->{skip_installed},'skip-satisfied!'=>\$self->{skip_satisfied},'reinstall'=>sub {$self->{skip_installed}=0},'interactive!'=>\$self->{interactive},'i|install'=>sub {$self->{cmd}='install'},'info'=>sub {$self->{cmd}='info'},'look'=>sub {$self->{cmd}='look';$self->{skip_installed}=0},'U|uninstall'=>sub {$self->{cmd}='uninstall'},'self-upgrade'=>sub {$self->{action}='self_upgrade'},'uninst-shadows!'=>\$self->{uninstall_shadows},'lwp!'=>\$self->{try_lwp},'wget!'=>\$self->{try_wget},'curl!'=>\$self->{try_curl},'auto-cleanup=s'=>\$self->{auto_cleanup},'man-pages!'=>\$self->{pod2man},'scandeps'=>\$self->{scandeps},'showdeps'=>sub {$self->{showdeps}=1;$self->{skip_installed}=0},'format=s'=>\$self->{format},'save-dists=s'=>sub {$self->{save_dists}=$self->maybe_abs($_[1])},'skip-configure!'=>\$self->{skip_configure},'dev!'=>\$self->{dev_release},'metacpan!'=>\$self->{metacpan},'report-perl-version!'=>\$self->{report_perl_version},'configure-timeout=i'=>\$self->{configure_timeout},'build-timeout=i'=>\$self->{build_timeout},'test-timeout=i'=>\$self->{test_timeout},'with-develop'=>\$self->{with_develop},'without-develop'=>sub {$self->{with_develop}=0},'with-feature=s'=>sub {$self->{features}{$_[1]}=1},'without-feature=s'=>sub {$self->{features}{$_[1]}=0},'with-all-features'=>sub {$self->{features}{__all}=1},'pp|pureperl!'=>\$self->{pure_perl},"cpanfile=s"=>\$self->{cpanfile_path},$self->install_type_handlers,$self->build_args_handlers,);if (!@ARGV && $0 ne '-' &&!-t STDIN){push@ARGV,$self->load_argv_from_fh(\*STDIN);$self->{load_from_stdin}=1}$self->{argv}=\@ARGV}sub check_upgrade {my$self=shift;my$install_base=$ENV{PERL_LOCAL_LIB_ROOT}? $self->local_lib_target($ENV{PERL_LOCAL_LIB_ROOT}): $Config{installsitebin};if ($0 eq '-'){return}elsif ($0 !~ /^$install_base/){if ($0 =~ m!perlbrew/bin!){die <<DIE}else {die <<DIE}}}sub check_libs {my$self=shift;return if$self->{_checked}++;$self->bootstrap_local_lib}sub setup_verify {my$self=shift;my$has_modules=eval {require Module::Signature;require Digest::SHA;1};$self->{cpansign}=$self->which('cpansign');unless ($has_modules && $self->{cpansign}){warn "WARNING: Module::Signature and Digest::SHA is required for distribution verifications.\n";$self->{verify}=0}}sub parse_module_args {my($self,$module)=@_;$module =~ s/^([A-Za-z0-9_:]+)@([v\d\._]+)$/$1~== $2/;if ($module =~ /\~[v\d\._,\!<>= ]+$/){return split /\~/,$module,2}else {return$module,undef}}sub doit {my$self=shift;my$code;eval {$code=($self->_doit==0)};if (my$e=$@){warn$e;$code=1}return$code}sub _doit {my$self=shift;$self->setup_home;$self->init_tools;$self->setup_verify if$self->{verify};if (my$action=$self->{action}){$self->$action()and return 1}return$self->show_help(1)unless @{$self->{argv}}or $self->{load_from_stdin};$self->configure_mirrors;my$cwd=Cwd::cwd;my@fail;for my$module (@{$self->{argv}}){if ($module =~ s/\.pm$//i){my ($volume,$dirs,$file)=File::Spec->splitpath($module);$module=join '::',grep {$_}File::Spec->splitdir($dirs),$file}($module,my$version)=$self->parse_module_args($module);$self->chdir($cwd);if ($self->{cmd}eq 'uninstall'){$self->uninstall_module($module)or push@fail,$module}else {$self->install_module($module,0,$version)or push@fail,$module}}if ($self->{base}&& $self->{auto_cleanup}){$self->cleanup_workdirs}if ($self->{installed_dists}){my$dists=$self->{installed_dists}> 1 ? "distributions" : "distribution";$self->diag("$self->{installed_dists} $dists installed\n",1)}if ($self->{scandeps}){$self->dump_scandeps()}$self->chdir($cwd);return!@fail}sub setup_home {my$self=shift;$self->{home}=$self->env('HOME')if$self->env('HOME');unless (_writable($self->{home})){die "Can't write to cpanm home '$self->{home}': You should fix it with chown/chmod first.\n"}$self->{base}="$self->{home}/work/" .time .".$$";File::Path::mkpath([$self->{base}],0,0777);$self->{log}=File::Spec->catfile($self->{base},"build.log");my$final_log="$self->{home}/build.log";{open my$out,">$self->{log}" or die "$self->{log}: $!"}if (CAN_SYMLINK){my$build_link="$self->{home}/latest-build";unlink$build_link;symlink$self->{base},$build_link;unlink$final_log;symlink$self->{log},$final_log}else {my$log=$self->{log};my$home=$self->{home};$self->{at_exit}=sub {my$self=shift;my$temp_log="$home/build.log." .time .".$$";File::Copy::copy($log,$temp_log)&& unlink($final_log);rename($temp_log,$final_log)}}$self->chat("cpanm (App::cpanminus) $VERSION on perl $] built for $Config{archname}\n" ."Work directory is $self->{base}\n")}sub package_index_for {my ($self,$mirror)=@_;return$self->source_for($mirror)."/02packages.details.txt"}sub generate_mirror_index {my ($self,$mirror)=@_;my$file=$self->package_index_for($mirror);my$gz_file=$file .'.gz';my$index_mtime=(stat$gz_file)[9];unless (-e $file && (stat$file)[9]>= $index_mtime){$self->chat("Uncompressing index file...\n");if (eval {require Compress::Zlib}){my$gz=Compress::Zlib::gzopen($gz_file,"rb")or do {$self->diag_fail("$Compress::Zlib::gzerrno opening compressed index");return};open my$fh,'>',$file or do {$self->diag_fail("$! opening uncompressed index for write");return};my$buffer;while (my$status=$gz->gzread($buffer)){if ($status < 0){$self->diag_fail($gz->gzerror ." reading compressed index");return}print$fh $buffer}}else {if (system("gunzip -c $gz_file > $file")){$self->diag_fail("Cannot uncompress -- please install gunzip or Compress::Zlib");return}}utime$index_mtime,$index_mtime,$file}return 1}sub search_mirror_index {my ($self,$mirror,$module,$version)=@_;$self->search_mirror_index_file($self->package_index_for($mirror),$module,$version)}sub search_mirror_index_file {my($self,$file,$module,$version)=@_;open my$fh,'<',$file or return;my$found;while (<$fh>){if (m!^\Q$module\E\s+([\w\.]+)\s+(\S*)!m){$found=$self->cpan_module($module,$2,$1);last}}return$found unless$self->{cascade_search};if ($found){if ($self->satisfy_version($module,$found->{module_version},$version)){return$found}else {$self->chat("Found $module $found->{module_version} which doesn't satisfy $version.\n")}}return}sub with_version_range {my($self,$version)=@_;defined($version)&& $version =~ /(?:<|!=|==)/}sub encode_json {my($self,$data)=@_;require JSON::PP;my$json=JSON::PP::encode_json($data);$json =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;$json}sub version_to_query {my($self,$module,$version)=@_;require CPAN::Meta::Requirements;my$requirements=CPAN::Meta::Requirements->new;$requirements->add_string_requirement($module,$version || '0');my$req=$requirements->requirements_for_module($module);if ($req =~ s/^==\s*//){return {term=>{'module.version'=>$req },}}elsif ($req !~ /\s/){return {range=>{'module.version_numified'=>{'gte'=>$self->numify_ver_metacpan($req)}},}}else {my%ops=qw(< lt <= lte > gt >= gte);my(%range,@exclusion);my@requirements=split /,\s*/,$req;for my$r (@requirements){if ($r =~ s/^([<>]=?)\s*//){$range{$ops{$1}}=$self->numify_ver_metacpan($r)}elsif ($r =~ s/\!=\s*//){push@exclusion,$self->numify_ver_metacpan($r)}}my@filters=({range=>{'module.version_numified'=>\%range }},);if (@exclusion){push@filters,{not=>{or=>[map {+{term=>{'module.version_numified'=>$self->numify_ver_metacpan($_)}}}@exclusion ]},}}return@filters}}sub numify_ver_metacpan {my($self,$ver)=@_;$ver =~ s/_//g;version->new($ver)->numify}sub numify_ver {my($self,$ver)=@_;eval version->new($ver)->numify}sub maturity_filter {my($self,$module,$version)=@_;if ($version =~ /==/){return}elsif ($self->{dev_release}){return +{not=>{term=>{status=>'backpan' }}}}else {return ({not=>{term=>{status=>'backpan' }}},{term=>{maturity=>'released' }},)}}sub by_version {my%s=qw(latest 3 cpan 2 backpan 1);$b->{_score}<=> $a->{_score}|| $s{$b->{fields}{status}}<=> $s{$a->{fields}{status}}}sub by_first_come {$a->{fields}{date}cmp $b->{fields}{date}}sub by_date {$b->{fields}{date}cmp $a->{fields}{date}}sub find_best_match {my($self,$match,$version)=@_;return unless$match && @{$match->{hits}{hits}|| []};my@hits=$self->{dev_release}? sort {by_version || by_date}@{$match->{hits}{hits}}: sort {by_version || by_first_come}@{$match->{hits}{hits}};$hits[0]->{fields}}sub search_metacpan {my($self,$module,$version)=@_;require JSON::PP;$self->chat("Searching $module ($version) on metacpan ...\n");my$metacpan_uri='http://api.metacpan.org/v0';my@filter=$self->maturity_filter($module,$version);my$query={filtered=>{(@filter ? (filter=>{and=>\@filter }): ()),query=>{nested=>{score_mode=>'max',path=>'module',query=>{custom_score=>{metacpan_script=>"score_version_numified",query=>{constant_score=>{filter=>{and=>[{term=>{'module.authorized'=>JSON::PP::true()}},{term=>{'module.indexed'=>JSON::PP::true()}},{term=>{'module.name'=>$module }},$self->version_to_query($module,$version),]}}},}},}},}};my$module_uri="$metacpan_uri/file/_search?source=";$module_uri .= $self->encode_json({query=>$query,fields=>['date','release','author','module','status' ],});my($release,$author,$module_version);my$module_json=$self->get($module_uri);my$module_meta=eval {JSON::PP::decode_json($module_json)};my$match=$self->find_best_match($module_meta);if ($match){$release=$match->{release};$author=$match->{author};my$module_matched=(grep {$_->{name}eq $module}@{$match->{module}})[0];$module_version=$module_matched->{version}}unless ($release){$self->chat("! Could not find a release matching $module ($version) on MetaCPAN.\n");return}my$dist_uri="$metacpan_uri/release/_search?source=";$dist_uri .= $self->encode_json({filter=>{and=>[{term=>{'release.name'=>$release }},{term=>{'release.author'=>$author }},]},fields=>['download_url','stat','status' ],});my$dist_json=$self->get($dist_uri);my$dist_meta=eval {JSON::PP::decode_json($dist_json)};if ($dist_meta){$dist_meta=$dist_meta->{hits}{hits}[0]{fields}}if ($dist_meta && $dist_meta->{download_url}){(my$distfile=$dist_meta->{download_url})=~ s!.+/authors/id/!!;local$self->{mirrors}=$self->{mirrors};if ($dist_meta->{status}eq 'backpan'){$self->{mirrors}=['http://backpan.perl.org' ]}elsif ($dist_meta->{stat}{mtime}> time()-24*60*60){$self->{mirrors}=['http://cpan.metacpan.org' ]}return$self->cpan_module($module,$distfile,$module_version)}$self->diag_fail("Finding $module on metacpan failed.");return}sub search_database {my($self,$module,$version)=@_;my$found;if ($self->{dev_release}or $self->{metacpan}){$found=$self->search_metacpan($module,$version)and return$found;$found=$self->search_cpanmetadb($module,$version)and return$found}else {$found=$self->search_cpanmetadb($module,$version)and return$found;$found=$self->search_metacpan($module,$version)and return$found}}sub search_cpanmetadb {my($self,$module,$version)=@_;$self->chat("Searching $module ($version) on cpanmetadb ...\n");if ($self->with_version_range($version)){return$self->search_cpanmetadb_history($module,$version)}else {return$self->search_cpanmetadb_package($module,$version)}}sub search_cpanmetadb_package {my($self,$module,$version)=@_;require CPAN::Meta::YAML;(my$uri=$self->{cpanmetadb})=~ s{/?$}{/package/$module};my$yaml=$self->get($uri);my$meta=eval {CPAN::Meta::YAML::Load($yaml)};if ($meta && $meta->{distfile}){return$self->cpan_module($module,$meta->{distfile},$meta->{version})}$self->diag_fail("Finding $module on cpanmetadb failed.");return}sub search_cpanmetadb_history {my($self,$module,$version)=@_;(my$uri=$self->{cpanmetadb})=~ s{/?$}{/history/$module};my$content=$self->get($uri)or return;my@found;for my$line (split /\r?\n/,$content){if ($line =~ /^$module\s+(\S+)\s+(\S+)$/){push@found,{version=>$1,version_obj=>version::->parse($1),distfile=>$2,}}}return unless@found;$found[-1]->{latest}=1;my$match;for my$try (sort {$b->{version_obj}cmp $a->{version_obj}}@found){if ($self->satisfy_version($module,$try->{version_obj},$version)){local$self->{mirrors}=$self->{mirrors};unshift @{$self->{mirrors}},'http://backpan.perl.org' unless$try->{latest};return$self->cpan_module($module,$try->{distfile},$try->{version})}}$self->diag_fail("Finding $module ($version) on cpanmetadb failed.");return}sub search_module {my($self,$module,$version)=@_;if ($self->{mirror_index}){$self->mask_output(chat=>"Searching $module on mirror index $self->{mirror_index} ...\n");my$pkg=$self->search_mirror_index_file($self->{mirror_index},$module,$version);return$pkg if$pkg;unless ($self->{cascade_search}){$self->mask_output(diag_fail=>"Finding $module ($version) on mirror index $self->{mirror_index} failed.");return}}unless ($self->{mirror_only}){my$found=$self->search_database($module,$version);return$found if$found}MIRROR: for my$mirror (@{$self->{mirrors}}){$self->mask_output(chat=>"Searching $module on mirror $mirror ...\n");my$name='02packages.details.txt.gz';my$uri="$mirror/modules/$name";my$gz_file=$self->package_index_for($mirror).'.gz';unless ($self->{pkgs}{$uri}){$self->mask_output(chat=>"Downloading index file $uri ...\n");$self->mirror($uri,$gz_file);$self->generate_mirror_index($mirror)or next MIRROR;$self->{pkgs}{$uri}="!!retrieved!!"}my$pkg=$self->search_mirror_index($mirror,$module,$version);return$pkg if$pkg;$self->mask_output(diag_fail=>"Finding $module ($version) on mirror $mirror failed.")}return}sub source_for {my($self,$mirror)=@_;$mirror =~ s/[^\w\.\-]+/%/g;my$dir="$self->{home}/sources/$mirror";File::Path::mkpath([$dir ],0,0777);return$dir}sub load_argv_from_fh {my($self,$fh)=@_;my@argv;while(defined(my$line=<$fh>)){chomp$line;$line =~ s/#.+$//;$line =~ s/^\s+//;$line =~ s/\s+$//;push@argv,split ' ',$line if$line}return@argv}sub show_version {my$self=shift;print "cpanm (App::cpanminus) version $VERSION ($0)\n";print "perl version $] ($^X)\n\n";print "  \%Config:\n";for my$key (qw(archname installsitelib installsitebin installman1dir installman3dir sitearchexp sitelibexp vendorarch vendorlibexp archlibexp privlibexp)){print "    $key=$Config{$key}\n" if$Config{$key}}print "  \%ENV:\n";for my$key (grep /^PERL/,sort keys%ENV){print "    $key=$ENV{$key}\n"}print "  \@INC:\n";for my$inc (@INC){print "    $inc\n" unless ref($inc)eq 'CODE'}return 1}sub show_help {my$self=shift;if ($_[0]){print <<USAGE;return}print <<HELP;return 1}sub _writable {my$dir=shift;my@dir=File::Spec->splitdir($dir);while (@dir){$dir=File::Spec->catdir(@dir);if (-e $dir){return -w _}pop@dir}return}sub maybe_abs {my($self,$lib)=@_;if ($lib eq '_' or $lib =~ /^~/ or File::Spec->file_name_is_absolute($lib)){return$lib}else {return File::Spec->canonpath(File::Spec->catdir(Cwd::cwd(),$lib))}}sub local_lib_target {my($self,$root)=@_;(grep {$_ ne ''}split /\Q$Config{path_sep}/,$root)[0]}sub bootstrap_local_lib {my$self=shift;if ($self->{local_lib}){return$self->setup_local_lib($self->{local_lib})}if ($ENV{PERL_LOCAL_LIB_ROOT}&& $ENV{PERL_MM_OPT}){return$self->setup_local_lib($self->local_lib_target($ENV{PERL_LOCAL_LIB_ROOT}),1)}return if$self->{sudo}or (_writable($Config{installsitelib})and _writable($Config{installsitebin}));if ($ENV{PERL_MM_OPT}and ($ENV{MODULEBUILDRC}or $ENV{PERL_MB_OPT})){return}$self->setup_local_lib;$self->diag(<<DIAG,1);sleep 2}sub upgrade_toolchain {my($self,$config_deps)=@_;my%deps=map {$_->module=>$_}@$config_deps;my$reqs=CPAN::Meta::Requirements->from_string_hash({'Module::Build'=>'0.38','ExtUtils::MakeMaker'=>'6.58','ExtUtils::Install'=>'1.46',});if ($deps{"ExtUtils::MakeMaker"}){$deps{"ExtUtils::MakeMaker"}->merge_with($reqs)}elsif ($deps{"Module::Build"}){$deps{"Module::Build"}->merge_with($reqs);$deps{"ExtUtils::Install"}||= App::cpanminus::Dependency->new("ExtUtils::Install",0,'configure');$deps{"ExtUtils::Install"}->merge_with($reqs)}@$config_deps=values%deps}sub _core_only_inc {my($self,$base)=@_;require local::lib;(local::lib->resolve_path(local::lib->install_base_arch_path($base)),local::lib->resolve_path(local::lib->install_base_perl_path($base)),(!$self->{exclude_vendor}? grep {$_}@Config{qw(vendorarch vendorlibexp)}: ()),@Config{qw(archlibexp privlibexp)},)}sub _diff {my($self,$old,$new)=@_;my@diff;my%old=map {$_=>1}@$old;for my$n (@$new){push@diff,$n unless exists$old{$n}}@diff}sub _setup_local_lib_env {my($self,$base)=@_;$self->diag(<<WARN,1)if$base =~ /\s/;local$SIG{__WARN__}=sub {};local::lib->setup_env_hash_for($base,0)}sub setup_local_lib {my($self,$base,$no_env)=@_;$base=undef if$base eq '_';require local::lib;{local $0='cpanm';$base ||= "~/perl5";$base=local::lib->resolve_path($base);if ($self->{self_contained}){my@inc=$self->_core_only_inc($base);$self->{search_inc}=[@inc ]}else {$self->{search_inc}=[local::lib->install_base_arch_path($base),local::lib->install_base_perl_path($base),@INC,]}$self->_setup_local_lib_env($base)unless$no_env;$self->{local_lib}=$base}}sub prompt_bool {my($self,$mess,$def)=@_;my$val=$self->prompt($mess,$def);return lc$val eq 'y'}sub prompt {my($self,$mess,$def)=@_;my$isa_tty=-t STDIN && (-t STDOUT ||!(-f STDOUT || -c STDOUT));my$dispdef=defined$def ? "[$def] " : " ";$def=defined$def ? $def : "";if (!$self->{prompt}|| (!$isa_tty && eof STDIN)){return$def}local $|=1;local $\;my$ans;eval {local$SIG{ALRM}=sub {undef$ans;die "alarm\n"};print STDOUT "$mess $dispdef";alarm$self->{prompt_timeout}if$self->{prompt_timeout};$ans=<STDIN>;alarm 0};if (defined$ans){chomp$ans}else {print STDOUT "\n"}return (!defined$ans || $ans eq '')? $def : $ans}sub diag_ok {my($self,$msg)=@_;chomp$msg;$msg ||= "OK";if ($self->{in_progress}){$self->_diag("$msg\n");$self->{in_progress}=0}$self->log("-> $msg\n")}sub diag_fail {my($self,$msg,$always)=@_;chomp$msg;if ($self->{in_progress}){$self->_diag("FAIL\n");$self->{in_progress}=0}if ($msg){$self->_diag("! $msg\n",$always,1);$self->log("-> FAIL $msg\n")}}sub diag_progress {my($self,$msg)=@_;chomp$msg;$self->{in_progress}=1;$self->_diag("$msg ... ");$self->log("$msg\n")}sub _diag {my($self,$msg,$always,$error)=@_;my$fh=$error ? *STDERR : *STDOUT;print {$fh}$msg if$always or $self->{verbose}or!$self->{quiet}}sub diag {my($self,$msg,$always)=@_;$self->_diag($msg,$always);$self->log($msg)}sub chat {my$self=shift;print STDERR @_ if$self->{verbose};$self->log(@_)}sub mask_output {my$self=shift;my$method=shift;$self->$method($self->mask_uri_passwords(@_))}sub log {my$self=shift;open my$out,">>$self->{log}";print$out @_}sub run {my($self,$cmd)=@_;if (WIN32){$cmd=$self->shell_quote(@$cmd)if ref$cmd eq 'ARRAY';unless ($self->{verbose}){$cmd .= " >> " .$self->shell_quote($self->{log})." 2>&1"}!system$cmd}else {my$pid=fork;if ($pid){waitpid$pid,0;return!$?}else {$self->run_exec($cmd)}}}sub run_exec {my($self,$cmd)=@_;if (ref$cmd eq 'ARRAY'){unless ($self->{verbose}){open my$logfh,">>",$self->{log};open STDERR,'>&',$logfh;open STDOUT,'>&',$logfh;close$logfh}exec @$cmd}else {unless ($self->{verbose}){$cmd .= " >> " .$self->shell_quote($self->{log})." 2>&1"}exec$cmd}}sub run_timeout {my($self,$cmd,$timeout)=@_;return$self->run($cmd)if WIN32 || $self->{verbose}||!$timeout;my$pid=fork;if ($pid){eval {local$SIG{ALRM}=sub {die "alarm\n"};alarm$timeout;waitpid$pid,0;alarm 0};if ($@ && $@ eq "alarm\n"){$self->diag_fail("Timed out (> ${timeout}s). Use --verbose to retry.");local$SIG{TERM}='IGNORE';kill TERM=>0;waitpid$pid,0;return}return!$?}elsif ($pid==0){$self->run_exec($cmd)}else {$self->chat("! fork failed: falling back to system()\n");$self->run($cmd)}}sub append_args {my($self,$cmd,$phase)=@_;if (my$args=$self->{build_args}{$phase}){$cmd=join ' ',$self->shell_quote(@$cmd),$args}$cmd}sub configure {my($self,$cmd,$depth)=@_;local$ENV{PERL5_CPAN_IS_RUNNING}=local$ENV{PERL5_CPANPLUS_IS_RUNNING}=$$;local$ENV{PERL5_CPANM_IS_RUNNING}=$$;my$use_default=!$self->{interactive};local$ENV{PERL_MM_USE_DEFAULT}=$use_default;local$ENV{PERL_MM_OPT}=$ENV{PERL_MM_OPT};local$ENV{PERL_MB_OPT}=$ENV{PERL_MB_OPT};unless ($self->{pod2man}){$ENV{PERL_MM_OPT}.= " INSTALLMAN1DIR=none INSTALLMAN3DIR=none";$ENV{PERL_MB_OPT}.= " --config installman1dir= --config installsiteman1dir= --config installman3dir= --config installsiteman3dir="}if ($self->{pure_perl}){$ENV{PERL_MM_OPT}.= " PUREPERL_ONLY=1";$ENV{PERL_MB_OPT}.= " --pureperl-only"}$cmd=$self->append_args($cmd,'configure')if$depth==0;local$self->{verbose}=$self->{verbose}|| $self->{interactive};$self->run_timeout($cmd,$self->{configure_timeout})}sub build {my($self,$cmd,$distname,$depth)=@_;local$ENV{PERL_MM_USE_DEFAULT}=!$self->{interactive};$cmd=$self->append_args($cmd,'build')if$depth==0;return 1 if$self->run_timeout($cmd,$self->{build_timeout});while (1){my$ans=lc$self->prompt("Building $distname failed.\nYou can s)kip, r)etry, e)xamine build log, or l)ook ?","s");return if$ans eq 's';return$self->build($cmd,$distname,$depth)if$ans eq 'r';$self->show_build_log if$ans eq 'e';$self->look if$ans eq 'l'}}sub test {my($self,$cmd,$distname,$depth)=@_;return 1 if$self->{notest};local$ENV{PERL_MM_USE_DEFAULT}=!$self->{interactive};local$ENV{NONINTERACTIVE_TESTING}=!$self->{interactive};$cmd=$self->append_args($cmd,'test')if$depth==0;return 1 if$self->run_timeout($cmd,$self->{test_timeout});if ($self->{force}){$self->diag_fail("Testing $distname failed but installing it anyway.");return 1}else {$self->diag_fail;while (1){my$ans=lc$self->prompt("Testing $distname failed.\nYou can s)kip, r)etry, f)orce install, e)xamine build log, or l)ook ?","s");return if$ans eq 's';return$self->test($cmd,$distname,$depth)if$ans eq 'r';return 1 if$ans eq 'f';$self->show_build_log if$ans eq 'e';$self->look if$ans eq 'l'}}}sub install {my($self,$cmd,$uninst_opts,$depth)=@_;if ($depth==0 && $self->{test_only}){return 1}if ($self->{sudo}){unshift @$cmd,"sudo"}if ($self->{uninstall_shadows}&&!$ENV{PERL_MM_OPT}){push @$cmd,@$uninst_opts}$cmd=$self->append_args($cmd,'install')if$depth==0;$self->run($cmd)}sub look {my$self=shift;my$shell=$ENV{SHELL};$shell ||= $ENV{COMSPEC}if WIN32;if ($shell){my$cwd=Cwd::cwd;$self->diag("Entering $cwd with $shell\n");system$shell}else {$self->diag_fail("You don't seem to have a SHELL :/")}}sub show_build_log {my$self=shift;my@pagers=($ENV{PAGER},(WIN32 ? (): ('less')),'more');my$pager;while (@pagers){$pager=shift@pagers;next unless$pager;$pager=$self->which($pager);next unless$pager;last}if ($pager){system("$pager < $self->{log}")}else {$self->diag_fail("You don't seem to have a PAGER :/")}}sub chdir {my$self=shift;Cwd::chdir(File::Spec->canonpath($_[0]))or die "$_[0]: $!"}sub configure_mirrors {my$self=shift;unless (@{$self->{mirrors}}){$self->{mirrors}=['http://www.cpan.org' ]}for (@{$self->{mirrors}}){s!^/!file:///!;s!/$!!}}sub self_upgrade {my$self=shift;$self->check_upgrade;$self->{argv}=['App::cpanminus' ];return}sub install_module {my($self,$module,$depth,$version)=@_;$self->check_libs;if ($self->{seen}{$module}++){$self->chat("Already tried $module. Skipping.\n");return 1}if ($self->{skip_satisfied}){my($ok,$local)=$self->check_module($module,$version || 0);if ($ok){$self->diag("You have $module ($local)\n",1);return 1}}my$dist=$self->resolve_name($module,$version);unless ($dist){my$what=$module .($version ? " ($version)" : "");$self->diag_fail("Couldn't find module or a distribution $what",1);return}if ($dist->{distvname}&& $self->{seen}{$dist->{distvname}}++){$self->chat("Already tried $dist->{distvname}. Skipping.\n");return 1}if ($self->{cmd}eq 'info'){print$self->format_dist($dist),"\n";return 1}$dist->{depth}=$depth;if ($dist->{module}){unless ($self->satisfy_version($dist->{module},$dist->{module_version},$version)){$self->diag("Found $dist->{module} $dist->{module_version} which doesn't satisfy $version.\n",1);return}my$cmp=$version ? "==" : "";my$requirement=$dist->{module_version}? "$cmp$dist->{module_version}" : 0;my($ok,$local)=$self->check_module($dist->{module},$requirement);if ($self->{skip_installed}&& $ok){$self->diag("$dist->{module} is up to date. ($local)\n",1);return 1}}if ($dist->{dist}eq 'perl'){$self->diag("skipping $dist->{pathname}\n");return 1}$self->diag("--> Working on $module\n");$dist->{dir}||= $self->fetch_module($dist);unless ($dist->{dir}){$self->diag_fail("Failed to fetch distribution $dist->{distvname}",1);return}$self->chat("Entering $dist->{dir}\n");$self->chdir($self->{base});$self->chdir($dist->{dir});if ($self->{cmd}eq 'look'){$self->look;return 1}return$self->build_stuff($module,$dist,$depth)}sub uninstall_search_path {my$self=shift;$self->{local_lib}? (local::lib->install_base_arch_path($self->{local_lib}),local::lib->install_base_perl_path($self->{local_lib})): @Config{qw(installsitearch installsitelib)}}sub uninstall_module {my ($self,$module)=@_;$self->check_libs;my@inc=$self->uninstall_search_path;my($metadata,$packlist)=$self->packlists_containing($module,\@inc);unless ($packlist){$self->diag_fail(<<DIAG,1);return}my@uninst_files=$self->uninstall_target($metadata,$packlist);$self->ask_permission($module,\@uninst_files)or return;$self->uninstall_files(@uninst_files,$packlist);$self->diag("Successfully uninstalled $module\n",1);return 1}sub packlists_containing {my($self,$module,$inc)=@_;require Module::Metadata;my$metadata=Module::Metadata->new_from_module($module,inc=>$inc)or return;my$packlist;my$wanted=sub {return unless $_ eq '.packlist' && -f $_;for my$file ($self->unpack_packlist($File::Find::name)){$packlist ||= $File::Find::name if$file eq $metadata->filename}};{require File::pushd;my$pushd=File::pushd::pushd();my@search=grep -d $_,map File::Spec->catdir($_,'auto'),@$inc;File::Find::find($wanted,@search)}return$metadata,$packlist}sub uninstall_target {my($self,$metadata,$packlist)=@_;if ($self->has_shadow_install($metadata)or $self->{local_lib}){grep$self->should_unlink($_),$self->unpack_packlist($packlist)}else {$self->unpack_packlist($packlist)}}sub has_shadow_install {my($self,$metadata)=@_;my@shadow=grep defined,map Module::Metadata->new_from_module($metadata->name,inc=>[$_]),@INC;@shadow >= 2}sub should_unlink {my($self,$file)=@_;if ($self->{local_lib}){$file =~ /^\Q$self->{local_lib}\E/}else {!(grep$file =~ /^\Q$_\E/,@Config{qw(installbin installscript installman1dir installman3dir)})}}sub ask_permission {my ($self,$module,$files)=@_;$self->diag("$module contains the following files:\n\n");for my$file (@$files){$self->diag("  $file\n")}$self->diag("\n");return 'force uninstall' if$self->{force};local$self->{prompt}=1;return$self->prompt_bool("Are you sure you want to uninstall $module?",'y')}sub unpack_packlist {my ($self,$packlist)=@_;open my$fh,'<',$packlist or die "$packlist: $!";map {chomp;$_}<$fh>}sub uninstall_files {my ($self,@files)=@_;$self->diag("\n");for my$file (@files){$self->diag("Unlink: $file\n");unlink$file or $self->diag_fail("$!: $file")}$self->diag("\n");return 1}sub format_dist {my($self,$dist)=@_;return "$dist->{cpanid}/$dist->{filename}"}sub trim {local $_=shift;tr/\n/ /d;s/^\s*|\s*$//g;$_}sub fetch_module {my($self,$dist)=@_;$self->chdir($self->{base});for my$uri (@{$dist->{uris}}){$self->mask_output(diag_progress=>"Fetching $uri");my$filename=$dist->{filename}|| $uri;my$name=File::Basename::basename($filename);my$cancelled;my$fetch=sub {my$file;eval {local$SIG{INT}=sub {$cancelled=1;die "SIGINT\n"};$self->mirror($uri,$name);$file=$name if -e $name};$self->diag("ERROR: " .trim("$@")."\n",1)if $@ && $@ ne "SIGINT\n";return$file};my($try,$file);while ($try++ < 3){$file=$fetch->();last if$cancelled or $file;$self->mask_output(diag_fail=>"Download $uri failed. Retrying ... ")}if ($cancelled){$self->diag_fail("Download cancelled.");return}unless ($file){$self->mask_output(diag_fail=>"Failed to download $uri");next}$self->diag_ok;$dist->{local_path}=File::Spec->rel2abs($name);my$dir=$self->unpack($file,$uri,$dist);next unless$dir;if (my$save=$self->{save_dists}){my$path=$dist->{pathname}? "$save/authors/id/$dist->{pathname}" : "$save/vendor/$file";$self->chat("Copying $name to $path\n");File::Path::mkpath([File::Basename::dirname($path)],0,0777);File::Copy::copy($file,$path)or warn $!}return$dist,$dir}}sub unpack {my($self,$file,$uri,$dist)=@_;if ($self->{verify}){$self->verify_archive($file,$uri,$dist)or return}$self->chat("Unpacking $file\n");my$dir=$file =~ /\.zip/i ? $self->unzip($file): $self->untar($file);unless ($dir){$self->diag_fail("Failed to unpack $file: no directory")}return$dir}sub verify_checksums_signature {my($self,$chk_file)=@_;require Module::Signature;$self->chat("Verifying the signature of CHECKSUMS\n");my$rv=eval {local$SIG{__WARN__}=sub {};my$v=Module::Signature::_verify($chk_file);$v==Module::Signature::SIGNATURE_OK()};if ($rv){$self->chat("Verified OK!\n")}else {$self->diag_fail("Verifying CHECKSUMS signature failed: $rv\n");return}return 1}sub verify_archive {my($self,$file,$uri,$dist)=@_;unless ($dist->{cpanid}){$self->chat("Archive '$file' does not seem to be from PAUSE. Skip verification.\n");return 1}(my$mirror=$uri)=~ s!/authors/id.*$!!;(my$chksum_uri=$uri)=~ s!/[^/]*$!/CHECKSUMS!;my$chk_file=$self->source_for($mirror)."/$dist->{cpanid}.CHECKSUMS";$self->mask_output(diag_progress=>"Fetching $chksum_uri");$self->mirror($chksum_uri,$chk_file);unless (-e $chk_file){$self->diag_fail("Fetching $chksum_uri failed.\n");return}$self->diag_ok;$self->verify_checksums_signature($chk_file)or return;$self->verify_checksum($file,$chk_file)}sub verify_checksum {my($self,$file,$chk_file)=@_;$self->chat("Verifying the SHA1 for $file\n");open my$fh,"<$chk_file" or die "$chk_file: $!";my$data=join '',<$fh>;$data =~ s/\015?\012/\n/g;require Safe;my$chksum=Safe->new->reval($data);if (!ref$chksum or ref$chksum ne 'HASH'){$self->diag_fail("! Checksum file downloaded from $chk_file is broken.\n");return}if (my$sha=$chksum->{$file}{sha256}){my$hex=$self->sha1_for($file);if ($hex eq $sha){$self->chat("Checksum for $file: Verified!\n")}else {$self->diag_fail("Checksum mismatch for $file\n");return}}else {$self->chat("Checksum for $file not found in CHECKSUMS.\n");return}}sub sha1_for {my($self,$file)=@_;require Digest::SHA;open my$fh,"<",$file or die "$file: $!";my$dg=Digest::SHA->new(256);my($data);while (read($fh,$data,4096)){$dg->add($data)}return$dg->hexdigest}sub verify_signature {my($self,$dist)=@_;$self->diag_progress("Verifying the SIGNATURE file");my$out=`$self->{cpansign} -v --skip 2>&1`;$self->log($out);if ($out =~ /Signature verified OK/){$self->diag_ok("Verified OK");return 1}else {$self->diag_fail("SIGNATURE verificaion for $dist->{filename} failed\n");return}}sub resolve_name {my($self,$module,$version)=@_;if ($module =~ /(?:^git:|\.git(?:@.+)?$)/){return$self->git_uri($module)}if ($module =~ /^(ftp|https?|file):/){if ($module =~ m!authors/id/(.*)!){return$self->cpan_dist($1,$module)}else {return {uris=>[$module ]}}}if ($module =~ m!^[\./]! && -d $module){return {source=>'local',dir=>Cwd::abs_path($module),}}if (-f $module){return {source=>'local',uris=>["file://" .Cwd::abs_path($module)],}}if ($module =~ s!^cpan:///distfile/!!){return$self->cpan_dist($module)}if ($module =~ m!^(?:[A-Z]/[A-Z]{2}/)?([A-Z]{2}[\-A-Z0-9]*/.*)$!){return$self->cpan_dist($1)}return$self->search_module($module,$version)}sub cpan_module {my($self,$module,$dist,$version)=@_;my$dist=$self->cpan_dist($dist);$dist->{module}=$module;$dist->{module_version}=$version if$version && $version ne 'undef';return$dist}sub cpan_dist {my($self,$dist,$url)=@_;$dist =~ s!^([A-Z]{2})!substr($1,0,1)."/".substr($1,0,2)."/".$1!e;require CPAN::DistnameInfo;my$d=CPAN::DistnameInfo->new($dist);if ($url){$url=[$url ]unless ref$url eq 'ARRAY'}else {my$id=$d->cpanid;my$fn=substr($id,0,1)."/" .substr($id,0,2)."/" .$id ."/" .$d->filename;my@mirrors=@{$self->{mirrors}};my@urls=map "$_/authors/id/$fn",@mirrors;$url=\@urls,}return {$d->properties,source=>'cpan',uris=>$url,}}sub git_uri {my ($self,$uri)=@_;($uri,my$commitish)=split /(?<=\.git)@/i,$uri,2;my$dir=File::Temp::tempdir(CLEANUP=>1);$self->mask_output(diag_progress=>"Cloning $uri");$self->run(['git','clone',$uri,$dir ]);unless (-e "$dir/.git"){$self->diag_fail("Failed cloning git repository $uri",1);return}if ($commitish){require File::pushd;my$dir=File::pushd::pushd($dir);unless ($self->run(['git','checkout',$commitish ])){$self->diag_fail("Failed to checkout '$commitish' in git repository $uri\n");return}}$self->diag_ok;return {source=>'local',dir=>$dir,}}sub setup_module_build_patch {my$self=shift;open my$out,">$self->{base}/ModuleBuildSkipMan.pm" or die $!;print$out <<EOF}sub core_version_for {my($self,$module)=@_;require Module::CoreList;unless (exists$Module::CoreList::version{$]+0}){die sprintf("Module::CoreList %s (loaded from %s) doesn't seem to have entries for perl $]. " ."You're strongly recommended to upgrade Module::CoreList from CPAN.\n",$Module::CoreList::VERSION,$INC{"Module/CoreList.pm"})}unless (exists$Module::CoreList::version{$]+0}{$module}){return -1}return$Module::CoreList::version{$]+0}{$module}}sub search_inc {my$self=shift;$self->{search_inc}||= do {if (defined$::Bin){[grep!/^\Q$::Bin\E\/..\/(?:fat)?lib$/,@INC]}else {[@INC]}}}sub check_module {my($self,$mod,$want_ver)=@_;require Module::Metadata;my$meta=Module::Metadata->new_from_module($mod,inc=>$self->search_inc)or return 0,undef;my$version=$meta->version;if ($self->{self_contained}&& $self->loaded_from_perl_lib($meta)){$version=$self->core_version_for($mod);return 0,undef if$version && $version==-1}$self->{local_versions}{$mod}=$version;if ($self->is_deprecated($meta)){return 0,$version}elsif ($self->satisfy_version($mod,$version,$want_ver)){return 1,($version || 'undef')}else {return 0,$version}}sub satisfy_version {my($self,$mod,$version,$want_ver)=@_;$want_ver='0' unless defined($want_ver)&& length($want_ver);require CPAN::Meta::Requirements;my$requirements=CPAN::Meta::Requirements->new;$requirements->add_string_requirement($mod,$want_ver);$requirements->accepts_module($mod,$version)}sub unsatisfy_how {my($self,$ver,$want_ver)=@_;if ($want_ver =~ /^[v0-9\.\_]+$/){return "$ver < $want_ver"}else {return "$ver doesn't satisfy $want_ver"}}sub is_deprecated {my($self,$meta)=@_;my$deprecated=eval {require Module::CoreList;Module::CoreList::is_deprecated($meta->{module})};return$deprecated && $self->loaded_from_perl_lib($meta)}sub loaded_from_perl_lib {my($self,$meta)=@_;require Config;my@dirs=qw(archlibexp privlibexp);if ($self->{self_contained}&&!$self->{exclude_vendor}&& $Config{vendorarch}){unshift@dirs,qw(vendorarch vendorlibexp)}for my$dir (@dirs){my$confdir=$Config{$dir};if ($confdir eq substr($meta->filename,0,length($confdir))){return 1}}return}sub should_install {my($self,$mod,$ver)=@_;$self->chat("Checking if you have $mod $ver ... ");my($ok,$local)=$self->check_module($mod,$ver);if ($ok){$self->chat("Yes ($local)\n")}elsif ($local){$self->chat("No (" .$self->unsatisfy_how($local,$ver).")\n")}else {$self->chat("No\n")}return$mod unless$ok;return}sub check_perl_version {my($self,$version)=@_;require CPAN::Meta::Requirements;my$req=CPAN::Meta::Requirements->from_string_hash({perl=>$version });$req->accepts_module(perl=>$])}sub install_deps {my($self,$dir,$depth,@deps)=@_;my(@install,%seen,@fail);for my$dep (@deps){next if$seen{$dep->module};if ($dep->module eq 'perl'){if ($dep->is_requirement &&!$self->check_perl_version($dep->version)){$self->diag("Needs perl @{[$dep->version]}, you have $]\n");push@fail,'perl'}}elsif ($self->should_install($dep->module,$dep->version)){push@install,$dep;$seen{$dep->module}=1}}if (@install){$self->diag("==> Found dependencies: " .join(", ",map $_->module,@install)."\n")}for my$dep (@install){$self->install_module($dep->module,$depth + 1,$dep->version)}$self->chdir($self->{base});$self->chdir($dir)if$dir;if ($self->{scandeps}){return 1}my@not_ok=$self->unsatisfied_deps(@deps);if (@not_ok){return 0,\@not_ok}else {return 1}}sub unsatisfied_deps {my($self,@deps)=@_;require CPAN::Meta::Check;require CPAN::Meta::Requirements;my$reqs=CPAN::Meta::Requirements->new;for my$dep (grep $_->is_requirement,@deps){$reqs->add_string_requirement($dep->module=>$dep->requires_version || '0')}my$ret=CPAN::Meta::Check::check_requirements($reqs,'requires',$self->{search_inc});grep defined,values %$ret}sub install_deps_bailout {my($self,$target,$dir,$depth,@deps)=@_;my($ok,$fail)=$self->install_deps($dir,$depth,@deps);if (!$ok){$self->diag_fail("Installing the dependencies failed: " .join(", ",@$fail),1);unless ($self->prompt_bool("Do you want to continue building $target anyway?","n")){$self->diag_fail("Bailing out the installation for $target.",1);return}}return 1}sub build_stuff {my($self,$stuff,$dist,$depth)=@_;if ($self->{verify}&& -e 'SIGNATURE'){$self->verify_signature($dist)or return}require CPAN::Meta;my($meta_file)=grep -f,qw(META.json META.yml);if ($meta_file){$self->chat("Checking configure dependencies from $meta_file\n");$dist->{cpanmeta}=eval {CPAN::Meta->load_file($meta_file)}}elsif ($dist->{dist}&& $dist->{version}){$self->chat("META.yml/json not found. Creating skeleton for it.\n");$dist->{cpanmeta}=CPAN::Meta->new({name=>$dist->{dist},version=>$dist->{version}})}$dist->{meta}=$dist->{cpanmeta}? $dist->{cpanmeta}->as_struct : {};my@config_deps;if ($dist->{cpanmeta}){push@config_deps,App::cpanminus::Dependency->from_prereqs($dist->{cpanmeta}->effective_prereqs,['configure'],$self->{install_types},)}if (-e 'Build.PL' &&!$self->should_use_mm($dist->{dist})&&!@config_deps){push@config_deps,App::cpanminus::Dependency->from_versions({'Module::Build'=>'0.38' },'configure',)}$self->upgrade_toolchain(\@config_deps);my$target=$dist->{meta}{name}? "$dist->{meta}{name}-$dist->{meta}{version}" : $dist->{dir};{$self->install_deps_bailout($target,$dist->{dir},$depth,@config_deps)or return}$self->diag_progress("Configuring $target");my$configure_state=$self->configure_this($dist,$depth);$self->diag_ok($configure_state->{configured_ok}? "OK" : "N/A");if ($dist->{cpanmeta}&& $dist->{source}eq 'cpan'){$dist->{provides}=$dist->{cpanmeta}{provides}|| $self->extract_packages($dist->{cpanmeta},".")}my$root_target=(($self->{installdeps}or $self->{showdeps})and $depth==0);$dist->{want_phases}=$self->{notest}&&!$root_target ? [qw(build runtime)]: [qw(build test runtime)];push @{$dist->{want_phases}},'develop' if$self->{with_develop}&& $depth==0;my@deps=$self->find_prereqs($dist);my$module_name=$self->find_module_name($configure_state)|| $dist->{meta}{name};$module_name =~ s/-/::/g;if ($self->{showdeps}){for my$dep (@config_deps,@deps){print$dep->module,($dep->version ? ("~".$dep->version): ""),"\n"}return 1}my$distname=$dist->{meta}{name}? "$dist->{meta}{name}-$dist->{meta}{version}" : $stuff;my$walkup;if ($self->{scandeps}){$walkup=$self->scandeps_append_child($dist)}$self->install_deps_bailout($distname,$dist->{dir},$depth,@deps)or return;if ($self->{scandeps}){unless ($configure_state->{configured_ok}){my$diag=<<DIAG;if (@config_deps){my@tree=@{$self->{scandeps_tree}};$diag .= "!\n" .join("",map "! * $_->[0]{module}\n",@tree[0..$#tree-1])if@tree}$self->diag("!\n$diag!\n",1)}$walkup->();return 1}if ($self->{installdeps}&& $depth==0){if ($configure_state->{configured_ok}){$self->diag("<== Installed dependencies for $stuff. Finishing.\n");return 1}else {$self->diag("! Configuring $distname failed. See $self->{log} for details.\n",1);return}}my$installed;if ($configure_state->{use_module_build}&& -e 'Build' && -f _){$self->diag_progress("Building " .($self->{notest}? "" : "and testing ").$distname);$self->build([$self->{perl},"./Build" ],$distname,$depth)&& $self->test([$self->{perl},"./Build","test" ],$distname,$depth)&& $self->install([$self->{perl},"./Build","install" ],["--uninst",1 ],$depth)&& $installed++}elsif ($self->{make}&& -e 'Makefile'){$self->diag_progress("Building " .($self->{notest}? "" : "and testing ").$distname);$self->build([$self->{make}],$distname,$depth)&& $self->test([$self->{make},"test" ],$distname,$depth)&& $self->install([$self->{make},"install" ],["UNINST=1" ],$depth)&& $installed++}else {my$why;my$configure_failed=$configure_state->{configured}&&!$configure_state->{configured_ok};if ($configure_failed){$why="Configure failed for $distname."}elsif ($self->{make}){$why="The distribution doesn't have a proper Makefile.PL/Build.PL"}else {$why="Can't configure the distribution. You probably need to have 'make'."}$self->diag_fail("$why See $self->{log} for details.",1);return}if ($installed && $self->{test_only}){$self->diag_ok;$self->diag("Successfully tested $distname\n",1)}elsif ($installed){my$local=$self->{local_versions}{$dist->{module}|| ''};my$version=$dist->{module_version}|| $dist->{meta}{version}|| $dist->{version};my$reinstall=$local && ($local eq $version);my$action=$local &&!$reinstall ? $self->numify_ver($version)< $self->numify_ver($local)? "downgraded" : "upgraded" : undef;my$how=$reinstall ? "reinstalled $distname" : $local ? "installed $distname ($action from $local)" : "installed $distname" ;my$msg="Successfully $how";$self->diag_ok;$self->diag("$msg\n",1);$self->{installed_dists}++;$self->save_meta($stuff,$dist,$module_name,\@config_deps,\@deps);return 1}else {my$what=$self->{test_only}? "Testing" : "Installing";$self->diag_fail("$what $stuff failed. See $self->{log} for details. Retry with --force to force install it.",1);return}}sub perl_requirements {my($self,@requires)=@_;my@perl;for my$requires (grep defined,@requires){if (exists$requires->{perl}){push@perl,App::cpanminus::Dependency->new(perl=>$requires->{perl})}}return@perl}sub should_use_mm {my($self,$dist)=@_;my%should_use_mm=map {$_=>1}qw(version ExtUtils-ParseXS ExtUtils-Install ExtUtils-Manifest);$should_use_mm{$dist}}sub configure_this {my($self,$dist,$depth)=@_;if (-e $self->{cpanfile_path}&& $self->{installdeps}&& $depth==0){require Module::CPANfile;$dist->{cpanfile}=eval {Module::CPANfile->load($self->{cpanfile_path})};$self->diag_fail($@,1)if $@;return {configured=>1,configured_ok=>!!$dist->{cpanfile},use_module_build=>0,}}if ($self->{skip_configure}){my$eumm=-e 'Makefile';my$mb=-e 'Build' && -f _;return {configured=>1,configured_ok=>$eumm || $mb,use_module_build=>$mb,}}my$state={};my$try_eumm=sub {if (-e 'Makefile.PL'){$self->chat("Running Makefile.PL\n");if ($self->configure([$self->{perl},"Makefile.PL" ],$depth)){$state->{configured_ok}=-e 'Makefile'}$state->{configured}++}};my$try_mb=sub {if (-e 'Build.PL'){$self->chat("Running Build.PL\n");if ($self->configure([$self->{perl},"Build.PL" ],$depth)){$state->{configured_ok}=-e 'Build' && -f _}$state->{use_module_build}++;$state->{configured}++}};my@try;if ($dist->{dist}&& $self->should_use_mm($dist->{dist})){@try=($try_eumm,$try_mb)}else {@try=($try_mb,$try_eumm)}for my$try (@try){$try->();last if$state->{configured_ok}}unless ($state->{configured_ok}){while (1){my$ans=lc$self->prompt("Configuring $dist->{dist} failed.\nYou can s)kip, r)etry, e)xamine build log, or l)ook ?","s");last if$ans eq 's';return$self->configure_this($dist,$depth)if$ans eq 'r';$self->show_build_log if$ans eq 'e';$self->look if$ans eq 'l'}}return$state}sub find_module_name {my($self,$state)=@_;return unless$state->{configured_ok};if ($state->{use_module_build}&& -e "_build/build_params"){my$params=do {open my$in,"_build/build_params";$self->safe_eval(join "",<$in>)};return eval {$params->[2]{module_name}}|| undef}elsif (-e "Makefile"){open my$mf,"Makefile";while (<$mf>){if (/^\#\s+NAME\s+=>\s+(.*)/){return$self->safe_eval($1)}}}return}sub list_files {my$self=shift;if (-e 'MANIFEST'){require ExtUtils::Manifest;my$manifest=eval {ExtUtils::Manifest::manifind()}|| {};return sort {lc$a cmp lc$b}keys %$manifest}else {require File::Find;my@files;my$finder=sub {my$name=$File::Find::name;$name =~ s!\.[/\\]!!;push@files,$name};File::Find::find($finder,".");return sort {lc$a cmp lc$b}@files}}sub extract_packages {my($self,$meta,$dir)=@_;my$try=sub {my$file=shift;return 0 if$file =~ m!^(?:x?t|inc|local|perl5|fatlib|_build)/!;return 1 unless$meta->{no_index};return 0 if grep {$file =~ m!^$_/!}@{$meta->{no_index}{directory}|| []};return 0 if grep {$file eq $_}@{$meta->{no_index}{file}|| []};return 1};require Parse::PMFile;my@files=grep {/\.pm(?:\.PL)?$/ && $try->($_)}$self->list_files;my$provides={};for my$file (@files){my$parser=Parse::PMFile->new($meta,{UNSAFE=>1,ALLOW_DEV_VERSION=>1 });my$packages=$parser->parse($file);while (my($package,$meta)=each %$packages){$provides->{$package}||= {file=>$meta->{infile},($meta->{version}eq 'undef')? (): (version=>$meta->{version}),}}}return$provides}sub save_meta {my($self,$module,$dist,$module_name,$config_deps,$build_deps)=@_;return unless$dist->{distvname}&& $dist->{source}eq 'cpan';my$base=($ENV{PERL_MM_OPT}|| '')=~ /INSTALL_BASE=/ ? ($self->install_base($ENV{PERL_MM_OPT})."/lib/perl5"): $Config{sitelibexp};my$provides=$dist->{provides};File::Path::mkpath("blib/meta",0,0777);my$local={name=>$module_name,target=>$module,version=>exists$provides->{$module_name}? ($provides->{$module_name}{version}|| $dist->{version}): $dist->{version},dist=>$dist->{distvname},pathname=>$dist->{pathname},provides=>$provides,};require JSON::PP;open my$fh,">","blib/meta/install.json" or die $!;print$fh JSON::PP::encode_json($local);if (-e "MYMETA.json"){File::Copy::copy("MYMETA.json","blib/meta/MYMETA.json")}my@cmd=(($self->{sudo}? 'sudo' : ()),$^X,'-MExtUtils::Install=install','-e',qq[install({ 'blib/meta' => '$base/$Config{archname}/.meta/$dist->{distvname}' })],);$self->run(\@cmd)}sub _merge_hashref {my($self,@hashrefs)=@_;my%hash;for my$h (@hashrefs){%hash=(%hash,%$h)}return \%hash}sub install_base {my($self,$mm_opt)=@_;$mm_opt =~ /INSTALL_BASE=(\S+)/ and return $1;die "Your PERL_MM_OPT doesn't contain INSTALL_BASE"}sub safe_eval {my($self,$code)=@_;eval$code}sub configure_features {my($self,$dist,@features)=@_;map $_->identifier,grep {$self->effective_feature($dist,$_)}@features}sub effective_feature {my($self,$dist,$feature)=@_;if ($dist->{depth}==0){my$value=$self->{features}{$feature->identifier};return$value if defined$value;return 1 if$self->{features}{__all}}if ($self->{interactive}){require CPAN::Meta::Requirements;$self->diag("[@{[ $feature->description ]}]\n",1);my$req=CPAN::Meta::Requirements->new;for my$phase (@{$dist->{want_phases}}){for my$type (@{$self->{install_types}}){$req->add_requirements($feature->prereqs->requirements_for($phase,$type))}}my$reqs=$req->as_string_hash;my@missing;for my$module (keys %$reqs){if ($self->should_install($module,$req->{$module})){push@missing,$module}}if (@missing){my$howmany=@missing;$self->diag("==> Found missing dependencies: " .join(", ",@missing)."\n",1);local$self->{prompt}=1;return$self->prompt_bool("Install the $howmany optional module(s)?","y")}}return}sub find_prereqs {my($self,$dist)=@_;my@deps=$self->extract_meta_prereqs($dist);if ($dist->{module}=~ /^Bundle::/i){push@deps,$self->bundle_deps($dist)}if ($self->{cpanfile_requirements}&&!$dist->{cpanfile}){for my$dep (@deps){$dep->merge_with($self->{cpanfile_requirements})}}return@deps}sub extract_meta_prereqs {my($self,$dist)=@_;if ($dist->{cpanfile}){my@features=$self->configure_features($dist,$dist->{cpanfile}->features);my$prereqs=$dist->{cpanfile}->prereqs_with(@features);$self->{cpanfile_requirements}=$prereqs->merged_requirements($dist->{want_phases},['requires']);return App::cpanminus::Dependency->from_prereqs($prereqs,$dist->{want_phases},$self->{install_types})}require CPAN::Meta;my@deps;my($meta_file)=grep -f,qw(MYMETA.json MYMETA.yml);if ($meta_file){$self->chat("Checking dependencies from $meta_file ...\n");my$mymeta=eval {CPAN::Meta->load_file($meta_file,{lazy_validation=>1 })};if ($mymeta){$dist->{meta}{name}=$mymeta->name;$dist->{meta}{version}=$mymeta->version;return$self->extract_prereqs($mymeta,$dist)}}if (-e '_build/prereqs'){$self->chat("Checking dependencies from _build/prereqs ...\n");my$prereqs=do {open my$in,"_build/prereqs";$self->safe_eval(join "",<$in>)};my$meta=CPAN::Meta->new({name=>$dist->{meta}{name},version=>$dist->{meta}{version},%$prereqs },{lazy_validation=>1 },);@deps=$self->extract_prereqs($meta,$dist)}elsif (-e 'Makefile'){$self->chat("Finding PREREQ from Makefile ...\n");open my$mf,"Makefile";while (<$mf>){if (/^\#\s+PREREQ_PM => \{\s*(.*?)\s*\}/){my@all;my@pairs=split ', ',$1;for (@pairs){my ($pkg,$v)=split '=>',$_;push@all,[$pkg,$v ]}my$list=join ", ",map {"'$_->[0]' => $_->[1]"}@all;my$prereq=$self->safe_eval("no strict; +{ $list }");push@deps,App::cpanminus::Dependency->from_versions($prereq)if$prereq;last}}}return@deps}sub bundle_deps {my($self,$dist)=@_;my@files;File::Find::find({wanted=>sub {push@files,File::Spec->rel2abs($_)if /\.pm/i},no_chdir=>1,},'.');my@deps;for my$file (@files){open my$pod,"<",$file or next;my$in_contents;while (<$pod>){if (/^=head\d\s+CONTENTS/){$in_contents=1}elsif (/^=/){$in_contents=0}elsif ($in_contents){/^(\S+)\s*(\S+)?/ and push@deps,App::cpanminus::Dependency->new($1,$self->maybe_version($2))}}}return@deps}sub maybe_version {my($self,$string)=@_;return$string && $string =~ /^\.?\d/ ? $string : undef}sub extract_prereqs {my($self,$meta,$dist)=@_;my@features=$self->configure_features($dist,$meta->features);my$prereqs=$self->soften_makemaker_prereqs($meta->effective_prereqs(\@features)->clone);return App::cpanminus::Dependency->from_prereqs($prereqs,$dist->{want_phases},$self->{install_types})}sub soften_makemaker_prereqs {my($self,$prereqs)=@_;return$prereqs unless -e "inc/Module/Install.pm";for my$phase (qw(build test runtime)){my$reqs=$prereqs->requirements_for($phase,'requires');if ($reqs->requirements_for_module('ExtUtils::MakeMaker')){$reqs->clear_requirement('ExtUtils::MakeMaker');$reqs->add_minimum('ExtUtils::MakeMaker'=>0)}}$prereqs}sub cleanup_workdirs {my$self=shift;my$expire=time - 24 * 60 * 60 * $self->{auto_cleanup};my@targets;opendir my$dh,"$self->{home}/work";while (my$e=readdir$dh){next if$e !~ /^(\d+)\.\d+$/;my$time=$1;if ($time < $expire){push@targets,"$self->{home}/work/$e"}}if (@targets){if (@targets >= 64){$self->diag("Expiring " .scalar(@targets)." work directories. This might take a while...\n")}else {$self->chat("Expiring " .scalar(@targets)." work directories.\n")}File::Path::rmtree(\@targets,0,0)}}sub scandeps_append_child {my($self,$dist)=@_;my$new_node=[$dist,[]];my$curr_node=$self->{scandeps_current}|| [undef,$self->{scandeps_tree}];push @{$curr_node->[1]},$new_node;$self->{scandeps_current}=$new_node;return sub {$self->{scandeps_current}=$curr_node}}sub dump_scandeps {my$self=shift;if ($self->{format}eq 'tree'){$self->walk_down(sub {my($dist,$depth)=@_;if ($depth==0){print "$dist->{distvname}\n"}else {print " " x ($depth - 1);print "\\_ $dist->{distvname}\n"}},1)}elsif ($self->{format}=~ /^dists?$/){$self->walk_down(sub {my($dist,$depth)=@_;print$self->format_dist($dist),"\n"},0)}elsif ($self->{format}eq 'json'){require JSON::PP;print JSON::PP::encode_json($self->{scandeps_tree})}elsif ($self->{format}eq 'yaml'){require YAML;print YAML::Dump($self->{scandeps_tree})}else {$self->diag("Unknown format: $self->{format}\n")}}sub walk_down {my($self,$cb,$pre)=@_;$self->_do_walk_down($self->{scandeps_tree},$cb,0,$pre)}sub _do_walk_down {my($self,$children,$cb,$depth,$pre)=@_;for my$node (@$children){$cb->($node->[0],$depth)if$pre;$self->_do_walk_down($node->[1],$cb,$depth + 1,$pre);$cb->($node->[0],$depth)unless$pre}}sub DESTROY {my$self=shift;$self->{at_exit}->($self)if$self->{at_exit}}sub shell_quote {my($self,@stuff)=@_;if (WIN32){join ' ',map {/^${quote}.+${quote}$/ ? $_ : ($quote .$_ .$quote)}@stuff}else {String::ShellQuote::shell_quote_best_effort(@stuff)}}sub which {my($self,$name)=@_;if (File::Spec->file_name_is_absolute($name)){if (-x $name &&!-d _){return$name}}my$exe_ext=$Config{_exe};for my$dir (File::Spec->path){my$fullpath=File::Spec->catfile($dir,$name);if ((-x $fullpath || -x ($fullpath .= $exe_ext))&&!-d _){if ($fullpath =~ /\s/){$fullpath=$self->shell_quote($fullpath)}return$fullpath}}return}sub get {my($self,$uri)=@_;if ($uri =~ /^file:/){$self->file_get($uri)}else {$self->{_backends}{get}->(@_)}}sub mirror {my($self,$uri,$local)=@_;if ($uri =~ /^file:/){$self->file_mirror($uri,$local)}else {$self->{_backends}{mirror}->(@_)}}sub untar {$_[0]->{_backends}{untar}->(@_)};sub unzip {$_[0]->{_backends}{unzip}->(@_)};sub uri_to_file {my($self,$uri)=@_;if ($uri =~ s!file:/+!!){$uri="/$uri" unless$uri =~ m![a-zA-Z]:!}return$uri}sub file_get {my($self,$uri)=@_;my$file=$self->uri_to_file($uri);open my$fh,"<$file" or return;join '',<$fh>}sub file_mirror {my($self,$uri,$path)=@_;my$file=$self->uri_to_file($uri);File::Copy::copy($file,$path)}sub has_working_lwp {my($self,$mirrors)=@_;my$https=grep /^https:/,@$mirrors;eval {require LWP::UserAgent;LWP::UserAgent->VERSION(5.802);require LWP::Protocol::https if$https;1}}sub init_tools {my$self=shift;return if$self->{initialized}++;if ($self->{make}=$self->which($Config{make})){$self->chat("You have make $self->{make}\n")}if ($self->{try_lwp}&& $self->has_working_lwp($self->{mirrors})){$self->chat("You have LWP $LWP::VERSION\n");my$ua=sub {LWP::UserAgent->new(parse_head=>0,env_proxy=>1,agent=>$self->agent,timeout=>30,@_,)};$self->{_backends}{get}=sub {my$self=shift;my$res=$ua->()->request(HTTP::Request->new(GET=>$_[0]));return unless$res->is_success;return$res->decoded_content};$self->{_backends}{mirror}=sub {my$self=shift;my$res=$ua->()->mirror(@_);die$res->content if$res->code==501;$res->code}}elsif ($self->{try_wget}and my$wget=$self->which('wget')){$self->chat("You have $wget\n");my@common=('--user-agent',$self->agent,'--retry-connrefused',($self->{verbose}? (): ('-q')),);$self->{_backends}{get}=sub {my($self,$uri)=@_;$self->safeexec(my$fh,$wget,$uri,@common,'-O','-')or die "wget $uri: $!";local $/;<$fh>};$self->{_backends}{mirror}=sub {my($self,$uri,$path)=@_;$self->safeexec(my$fh,$wget,$uri,@common,'-O',$path)or die "wget $uri: $!";local $/;<$fh>}}elsif ($self->{try_curl}and my$curl=$self->which('curl')){$self->chat("You have $curl\n");my@common=('--location','--user-agent',$self->agent,($self->{verbose}? (): '-s'),);$self->{_backends}{get}=sub {my($self,$uri)=@_;$self->safeexec(my$fh,$curl,@common,$uri)or die "curl $uri: $!";local $/;<$fh>};$self->{_backends}{mirror}=sub {my($self,$uri,$path)=@_;$self->safeexec(my$fh,$curl,@common,$uri,'-#','-o',$path)or die "curl $uri: $!";local $/;<$fh>}}else {require HTTP::Tiny;$self->chat("Falling back to HTTP::Tiny $HTTP::Tiny::VERSION\n");my%common=(agent=>$self->agent,);$self->{_backends}{get}=sub {my$self=shift;my$res=HTTP::Tiny->new(%common)->get($_[0]);return unless$res->{success};return$res->{content}};$self->{_backends}{mirror}=sub {my$self=shift;my$res=HTTP::Tiny->new(%common)->mirror(@_);return$res->{status}}}my$tar=$self->which('tar');my$tar_ver;my$maybe_bad_tar=sub {WIN32 || BAD_TAR || (($tar_ver=`$tar --version 2>/dev/null`)=~ /GNU.*1\.13/i)};if ($tar &&!$maybe_bad_tar->()){chomp$tar_ver;$self->chat("You have $tar: $tar_ver\n");$self->{_backends}{untar}=sub {my($self,$tarfile)=@_;my$xf=($self->{verbose}? 'v' : '')."xf";my$ar=$tarfile =~ /bz2$/ ? 'j' : 'z';my($root,@others)=`$tar ${ar}tf $tarfile` or return undef;FILE: {chomp$root;$root =~ s!^\./!!;$root =~ s{^(.+?)/.*$}{$1};if (!length($root)){$root=shift(@others);redo FILE if$root}}system "$tar $ar$xf $tarfile";return$root if -d $root;$self->diag_fail("Bad archive: $tarfile");return undef}}elsif ($tar and my$gzip=$self->which('gzip')and my$bzip2=$self->which('bzip2')){$self->chat("You have $tar, $gzip and $bzip2\n");$self->{_backends}{untar}=sub {my($self,$tarfile)=@_;my$x="x" .($self->{verbose}? 'v' : '')."f -";my$ar=$tarfile =~ /bz2$/ ? $bzip2 : $gzip;my($root,@others)=`$ar -dc $tarfile | $tar tf -` or return undef;FILE: {chomp$root;$root =~ s!^\./!!;$root =~ s{^(.+?)/.*$}{$1};if (!length($root)){$root=shift(@others);redo FILE if$root}}system "$ar -dc $tarfile | $tar $x";return$root if -d $root;$self->diag_fail("Bad archive: $tarfile");return undef}}elsif (eval {require Archive::Tar}){$self->chat("Falling back to Archive::Tar $Archive::Tar::VERSION\n");$self->{_backends}{untar}=sub {my$self=shift;my$t=Archive::Tar->new($_[0]);my($root,@others)=$t->list_files;FILE: {$root =~ s!^\./!!;$root =~ s{^(.+?)/.*$}{$1};if (!length($root)){$root=shift(@others);redo FILE if$root}}$t->extract;return -d $root ? $root : undef}}else {$self->{_backends}{untar}=sub {die "Failed to extract $_[1] - You need to have tar or Archive::Tar installed.\n"}}if (my$unzip=$self->which('unzip')){$self->chat("You have $unzip\n");$self->{_backends}{unzip}=sub {my($self,$zipfile)=@_;my$opt=$self->{verbose}? '' : '-q';my(undef,$root,@others)=`$unzip -t $zipfile` or return undef;chomp$root;$root =~ s{^\s+testing:\s+([^/]+)/.*?\s+OK$}{$1};system "$unzip $opt $zipfile";return$root if -d $root;$self->diag_fail("Bad archive: [$root] $zipfile");return undef}}else {$self->{_backends}{unzip}=sub {eval {require Archive::Zip}or die "Failed to extract $_[1] - You need to have unzip or Archive::Zip installed.\n";my($self,$file)=@_;my$zip=Archive::Zip->new();my$status;$status=$zip->read($file);$self->diag_fail("Read of file[$file] failed")if$status!=Archive::Zip::AZ_OK();my@members=$zip->members();for my$member (@members){my$af=$member->fileName();next if ($af =~ m!^(/|\.\./)!);$status=$member->extractToFileNamed($af);$self->diag_fail("Extracting of file[$af] from zipfile[$file failed")if$status!=Archive::Zip::AZ_OK()}my ($root)=$zip->membersMatching(qr<^[^/]+/$>);$root &&= $root->fileName;return -d $root ? $root : undef}}}sub safeexec {my$self=shift;my$rdr=$_[0]||= Symbol::gensym();if (WIN32){my$cmd=$self->shell_quote(@_[1..$#_]);return open($rdr,"$cmd |")}if (my$pid=open($rdr,'-|')){return$pid}elsif (defined$pid){exec(@_[1 .. $#_ ]);exit 1}else {return}}sub mask_uri_passwords {my($self,@strings)=@_;s{ (https?://) ([^:/]+) : [^@/]+ @ }{$1$2:********@}gx for@strings;return@strings}1;
479 33
   It appears your cpanm executable was installed via `perlbrew install-cpanm`.
480 34
   cpanm --self-upgrade won't upgrade the version of cpanm you're running.
481 35
   
... ...
@@ -483,9 +37,7 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
483 37
   
484 38
     perlbrew install-cpanm
485 39
   
486
-  WARN
487
-          } else {
488
-              warn <<WARN;
40
+  DIE
489 41
   You are running cpanm from the path where your current perl won't install executables to.
490 42
   Because of that, cpanm --self-upgrade won't upgrade the version of cpanm you're running.
491 43
   
... ...
@@ -494,11698 +46,463 @@ $fatpacked{"App/cpanminus/script.pm"} = <<'APP_CPANMINUS_SCRIPT';
494 46
   
495 47
   It means you either installed cpanm globally with system perl, or use distro packages such
496 48
   as rpm or apt-get, and you have to use them again to upgrade cpanm.
497
-  WARN
498
-          }
499
-      }
500
-  }
501
-  
502
-  sub check_libs {
503
-      my $self = shift;
504
-      return if $self->{_checked}++;
505
-  
506
-      $self->bootstrap_local_lib;
507
-      if (@{$self->{bootstrap_deps} || []}) {
508
-          local $self->{notest} = 1; # test failure in bootstrap should be tolerated
509
-          local $self->{scandeps} = 0;
510
-          $self->install_deps(Cwd::cwd, 0, @{$self->{bootstrap_deps}});
511
-      }
512
-  }
513
-  
514
-  sub setup_verify {
515
-      my $self = shift;
516
-  
517
-      my $has_modules = eval { require Module::Signature; require Digest::SHA; 1 };
518
-      $self->{cpansign} = $self->which('cpansign');
519
-  
520
-      unless ($has_modules && $self->{cpansign}) {
521
-          warn "WARNING: Module::Signature and Digest::SHA is required for distribution verifications.\n";
522
-          $self->{verify} = 0;
523
-      }
524
-  }
525
-  
526
-  sub parse_module_args {
527
-      my($self, $module) = @_;
528
-  
529
-      # Plack@1.2 -> Plack~"==1.2"
530
-      # BUT don't expand @ in git URLs
531
-      $module =~ s/^([A-Za-z0-9_:]+)@([v\d\._]+)$/$1~== $2/;
532
-  
533
-      # Plack~1.20, DBI~"> 1.0, <= 2.0"
534
-      if ($module =~ /\~[v\d\._,\!<>= ]+$/) {
535
-          return split /\~/, $module, 2;
536
-      } else {
537
-          return $module, undef;
538
-      }
539
-  }
540
-  
541
-  sub doit {
542
-      my $self = shift;
543
-  
544
-      $self->setup_home;
545
-      $self->init_tools;
546
-      $self->setup_verify if $self->{verify};
547
-  
548
-      if (my $action = $self->{action}) {
549
-          $self->$action() and return 1;
550
-      }
551
-  
552
-      $self->show_help(1)
553
-          unless @{$self->{argv}} or $self->{load_from_stdin};
554
-  
555
-      $self->configure_mirrors;
556
-  
557
-      my $cwd = Cwd::cwd;
558
-  
559
-      my @fail;
560
-      for my $module (@{$self->{argv}}) {
561
-          if ($module =~ s/\.pm$//i) {
562
-              my ($volume, $dirs, $file) = File::Spec->splitpath($module);
563
-              $module = join '::', grep { $_ } File::Spec->splitdir($dirs), $file;
564
-          }
565
-  
566
-          ($module, my $version) = $self->parse_module_args($module);
567
-          if ($self->{skip_satisfied}) {
568
-              $self->check_libs;
569
-              my($ok, $local) = $self->check_module($module, $version || 0);
570
-              if ($ok) {
571
-                  $self->diag("You have $module ($local)\n", 1);
572
-                  next;
573
-              }
574
-          }
575
-  
576
-          $self->chdir($cwd);
577
-          $self->install_module($module, 0, $version)
578
-              or push @fail, $module;
579
-      }
580
-  
581
-      if ($self->{base} && $self->{auto_cleanup}) {
582
-          $self->cleanup_workdirs;
583
-      }
584
-  
585
-      if ($self->{installed_dists}) {
586
-          my $dists = $self->{installed_dists} > 1 ? "distributions" : "distribution";
587
-          $self->diag("$self->{installed_dists} $dists installed\n", 1);
588
-      }
589
-  
590
-      if ($self->{scandeps}) {
591
-          $self->dump_scandeps();
592
-      }
593
-      # Workaround for older File::Temp's
594
-      # where creating a tempdir with an implicit $PWD
595
-      # causes tempdir non-cleanup if $PWD changes
596
-      # as paths are stored internally without being resolved
597
-      # absolutely.
598
-      # https://rt.cpan.org/Public/Bug/Display.html?id=44924
599
-      $self->chdir($cwd);
600
-  
601
-      return !@fail;
602
-  }
603
-  
604
-  sub setup_home {
605
-      my $self = shift;
606
-  
607
-      $self->{home} = $self->env('HOME') if $self->env('HOME');
608
-  
609
-      unless (_writable($self->{home})) {
610
-          die "Can't write to cpanm home '$self->{home}': You should fix it with chown/chmod first.\n";
611
-      }
612
-  
613
-      $self->{base} = "$self->{home}/work/" . time . ".$$";
614
-      File::Path::mkpath([ $self->{base} ], 0, 0777);
615
-  
616
-      my $link = "$self->{home}/latest-build";
617
-      eval { unlink $link; symlink $self->{base}, $link };
618
-  
619
-      $self->{log} = File::Spec->catfile($self->{home}, "build.log"); # because we use shell redirect
620
-  
621
-      {
622
-          my $log = $self->{log}; my $base = $self->{base};
623
-          $self->{at_exit} = sub {
624
-              my $self = shift;
625
-              File::Copy::copy($self->{log}, "$self->{base}/build.log");
626
-          };
627
-      }
628
-  
629
-      { open my $out, ">$self->{log}" or die "$self->{log}: $!" }
630
-  
631
-      $self->chat("cpanm (App::cpanminus) $VERSION on perl $] built for $Config{archname}\n" .
632
-                  "Work directory is $self->{base}\n");
633
-  }
634
-  
635
-  sub fetch_meta_sco {
636
-      my($self, $dist) = @_;
637
-      return if $self->{mirror_only};
638
-  
639
-      my $meta_yml = $self->get("http://search.cpan.org/meta/$dist->{distvname}/META.yml");
640
-      return $self->parse_meta_string($meta_yml);
641
-  }
642
-  
643
-  sub package_index_for {
644
-      my ($self, $mirror) = @_;
645
-      return $self->source_for($mirror) . "/02packages.details.txt";
646
-  }
647
-  
648
-  sub generate_mirror_index {
649
-      my ($self, $mirror) = @_;
650
-      my $file = $self->package_index_for($mirror);
651
-      my $gz_file = $file . '.gz';
652
-      my $index_mtime = (stat $gz_file)[9];
653
-  
654
-      unless (-e $file && (stat $file)[9] >= $index_mtime) {
655
-          $self->chat("Uncompressing index file...\n");
656
-          if (eval {require Compress::Zlib}) {
657
-              my $gz = Compress::Zlib::gzopen($gz_file, "rb")
658
-                  or do { $self->diag_fail("$Compress::Zlib::gzerrno opening compressed index"); return};
659
-              open my $fh, '>', $file
660
-                  or do { $self->diag_fail("$! opening uncompressed index for write"); return };
661
-              my $buffer;
662
-              while (my $status = $gz->gzread($buffer)) {
663
-                  if ($status < 0) {
664
-                      $self->diag_fail($gz->gzerror . " reading compressed index");
665
-                      return;
666
-                  }
667
-                  print $fh $buffer;
668
-              }
669
-          } else {
670
-              if (system("gunzip -c $gz_file > $file")) {
671
-                  $self->diag_fail("Cannot uncompress -- please install gunzip or Compress::Zlib");
672
-                  return;
673
-              }
674
-          }
675
-          utime $index_mtime, $index_mtime, $file;
676
-      }
677
-      return 1;
678
-  }
679
-  
680
-  sub search_mirror_index {
681
-      my ($self, $mirror, $module, $version) = @_;
682
-      $self->search_mirror_index_file($self->package_index_for($mirror), $module, $version);
683
-  }
684
-  
685
-  sub search_mirror_index_file {
686
-      my($self, $file, $module, $version) = @_;
687
-  
688
-      open my $fh, '<', $file or return;
689
-      my $found;
690
-      while (<$fh>) {
691
-          if (m!^\Q$module\E\s+([\w\.]+)\s+(\S*)!m) {
692
-              $found = $self->cpan_module($module, $2, $1);
693
-              last;
694
-          }
695
-      }
696
-  
697
-      return $found unless $self->{cascade_search};
698
-  
699
-      if ($found) {
700
-          if ($self->satisfy_version($module, $found->{module_version}, $version)) {
701
-              return $found;
702
-          } else {
703
-              $self->chat("Found $module $found->{module_version} which doesn't satisfy $version.\n");
704
-          }
705
-      }
706
-  
707
-      return;
708
-  }
709
-  
710
-  sub with_version_range {
711
-      my($self, $version) = @_;
712
-      defined($version) && $version =~ /[<>=]/;
713
-  }
714
-  
715
-  sub encode_json {
716
-      my($self, $data) = @_;
717
-      require JSON::PP;
718
-  
719
-      my $json = JSON::PP::encode_json($data);
720
-      $json =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg;
721
-      $json;
722
-  }
723
-  
724
-  # TODO extract this as a module?
725
-  sub version_to_query {
726
-      my($self, $module, $version) = @_;
727
-  
728
-      require CPAN::Meta::Requirements;
49
+  DIE
50
+  Usage: cpanm [options] Module [...]
729 51
   
730
-      my $requirements = CPAN::Meta::Requirements->new;
731
-      $requirements->add_string_requirement($module, $version || '0');
52
+  Try `cpanm --help` or `man cpanm` for more options.
53
+  USAGE
54
+  Usage: cpanm [options] Module [...]
732 55
   
733
-      my $req = $requirements->requirements_for_module($module);
734
-  
735
-      if ($req =~ s/^==\s*//) {
736
-          return {
737
-              term => { 'module.version' => $req },
738
-          };
739
-      } elsif ($req !~ /\s/) {
740
-          return {
741
-              range => { 'module.version_numified' => { 'gte' => $self->numify_ver($req) } },
742
-          };
743
-      } else {
744
-          my %ops = qw(< lt <= lte > gt >= gte);
745
-          my(%range, @exclusion);
746
-          my @requirements = split /,\s*/, $req;
747
-          for my $r (@requirements) {
748
-              if ($r =~ s/^([<>]=?)\s*//) {
749
-                  $range{$ops{$1}} = $self->numify_ver($r);
750
-              } elsif ($r =~ s/\!=\s*//) {
751
-                  push @exclusion, $self->numify_ver($r);
752
-              }
753
-          }
754
-  
755
-          my @filters= (
756
-              { range => { 'module.version_numified' => \%range } },
757
-          );
758
-  
759
-          if (@exclusion) {
760
-              push @filters, {
761
-                  not => { or => [ map { +{ term => { 'module.version_numified' => $self->numify_ver($_) } } } @exclusion ] },
762
-              };
763
-          }
764
-  
765
-          return @filters;
766
-      }
767
-  }
768
-  
769
-  sub numify_ver {
770
-      my($self, $ver) = @_;
771
-      version->new($ver)->numify;
772
-  }
773
-  
774
-  sub maturity_filter {
775
-      my($self, $module, $version) = @_;
776
-  
777
-      my @filters;
778
-  
779
-      # TODO: dev release should be enabled per dist
780
-      if (!$self->with_version_range($version) or $self->{dev_release}) {
781
-          # backpan'ed dev release are considered "cancelled"
782
-          push @filters, { not => { term => { status => 'backpan' } } };
783
-      }
784
-  
785
-      unless ($self->{dev_release} or $version =~ /==/) {
786
-          push @filters, { term => { maturity => 'released' } };
787
-      }
788
-  
789
-      return @filters;
790
-  }
791
-  
792
-  sub search_metacpan {
793
-      my($self, $module, $version) = @_;
794
-  
795
-      require JSON::PP;
796
-  
797
-      $self->chat("Searching $module ($version) on metacpan ...\n");
798
-  
799
-      my $metacpan_uri = 'http://api.metacpan.org/v0';
800
-  
801
-      my @filter = $self->maturity_filter($module, $version);
802
-  
803
-      my $query = { filtered => {
804
-          (@filter ? (filter => { and => \@filter }) : ()),
805
-          query => { nested => {
806
-              score_mode => 'max',
807
-              path => 'module',
808
-              query => { custom_score => {
809
-                  metacpan_script => "score_version_numified",
810
-                  query => { constant_score => {
811
-                      filter => { and => [
812
-                          { term => { 'module.authorized' => JSON::PP::true() } },
813
-                          { term => { 'module.indexed' => JSON::PP::true() } },
814
-                          { term => { 'module.name' => $module } },
815
-                          $self->version_to_query($module, $version),
816
-                      ] }
817
-                  } },
818
-              } },
819
-          } },
820
-      } };
821
-  
822
-      my $module_uri = "$metacpan_uri/file/_search?source=";
823
-      $module_uri .= $self->encode_json({
824
-          query => $query,
825
-          fields => [ 'release', 'module' ],
826
-      });
827
-  
828
-      my($release, $module_version);
829
-  
830
-      my $module_json = $self->get($module_uri);
831
-      my $module_meta = eval { JSON::PP::decode_json($module_json) };
832
-      my $match = $module_meta ? $module_meta->{hits}{hits}[0]{fields} : undef;
833
-      if ($match) {
834
-          $release = $match->{release};
835
-          my $module_matched = (grep { $_->{name} eq $module } @{$match->{module}})[0];
836
-          $module_version = $module_matched->{version};
837
-      }
838
-  
839
-      unless ($release) {
840
-          $self->chat("! Could not find a release matching $module ($version) on MetaCPAN.\n");
841
-          return;
842
-      }
843
-  
844
-      my $dist_uri = "$metacpan_uri/release/_search?source=";
845
-      $dist_uri .= $self->encode_json({
846
-          filter => {
847
-              term => { 'release.name' => $release },
848
-          },
849
-          fields => [ 'download_url', 'stat', 'status' ],
850
-      });
851
-  
852
-      my $dist_json = $self->get($dist_uri);
853
-      my $dist_meta = eval { JSON::PP::decode_json($dist_json) };
854
-  
855
-      if ($dist_meta) {
856
-          $dist_meta = $dist_meta->{hits}{hits}[0]{fields};
857
-      }
858
-      if ($dist_meta && $dist_meta->{download_url}) {
859
-          (my $distfile = $dist_meta->{download_url}) =~ s!.+/authors/id/!!;
860
-          local $self->{mirrors} = $self->{mirrors};
861
-          if ($dist_meta->{status} eq 'backpan') {
862
-              $self->{mirrors} = [ 'http://backpan.perl.org' ];
863
-          } elsif ($dist_meta->{stat}{mtime} > time()-24*60*60) {
864
-              $self->{mirrors} = [ 'http://cpan.metacpan.org' ];
865
-          }
866
-          return $self->cpan_module($module, $distfile, $module_version);
867
-      }
868
-  
869
-      $self->diag_fail("Finding $module on metacpan failed.");
870
-      return;
871
-  }
872
-  
873
-  sub search_database {
874
-      my($self, $module, $version) = @_;
875
-  
876
-      my $found;
877
-      my $range = ($self->with_version_range($version) || $self->{dev_release});
878
-  
879
-      if ($range or $self->{metacpan}) {
880
-          $found = $self->search_metacpan($module, $version)   and return $found;
881
-          $found = $self->search_cpanmetadb($module, $version) and return $found;
882
-      } else {
883
-          $found = $self->search_cpanmetadb($module, $version) and return $found;
884
-          $found = $self->search_metacpan($module, $version)   and return $found;
885
-      }
886
-  }
887
-  
888
-  sub search_cpanmetadb {
889
-      my($self, $module, $version) = @_;
890
-  
891
-      $self->chat("Searching $module on cpanmetadb ...\n");
892
-  
893
-      my $uri  = "http://cpanmetadb.plackperl.org/v1.0/package/$module";
894
-      my $yaml = $self->get($uri);
895
-      my $meta = $self->parse_meta_string($yaml);
896
-      if ($meta && $meta->{distfile}) {
897
-          return $self->cpan_module($module, $meta->{distfile}, $meta->{version});
898
-      }
899
-  
900
-      $self->diag_fail("Finding $module on cpanmetadb failed.");
901
-      return;
902
-  }
903
-  
904
-  sub search_module {
905
-      my($self, $module, $version) = @_;
906
-  
907
-      if ($self->{mirror_index}) {
908
-          $self->chat("Searching $module on mirror index $self->{mirror_index} ...\n");
909
-          my $pkg = $self->search_mirror_index_file($self->{mirror_index}, $module, $version);
910
-          return $pkg if $pkg;
911
-  
912
-          unless ($self->{cascade_search}) {
913
-             $self->diag_fail("Finding $module ($version) on mirror index $self->{mirror_index} failed.");
914
-             return;
915
-          }
916
-      }
917
-  
918
-      unless ($self->{mirror_only}) {
919
-          my $found = $self->search_database($module, $version);
920
-          return $found if $found;
921
-      }
922
-  
923
-      MIRROR: for my $mirror (@{ $self->{mirrors} }) {
924
-          $self->chat("Searching $module on mirror $mirror ...\n");
925
-          my $name = '02packages.details.txt.gz';
926
-          my $uri  = "$mirror/modules/$name";
927
-          my $gz_file = $self->package_index_for($mirror) . '.gz';
928
-  
929
-          unless ($self->{pkgs}{$uri}) {
930
-              $self->chat("Downloading index file $uri ...\n");
931
-              $self->mirror($uri, $gz_file);
932
-              $self->generate_mirror_index($mirror) or next MIRROR;
933
-              $self->{pkgs}{$uri} = "!!retrieved!!";
934
-          }
935
-  
936
-          my $pkg = $self->search_mirror_index($mirror, $module, $version);
937
-          return $pkg if $pkg;
938
-  
939
-          $self->diag_fail("Finding $module ($version) on mirror $mirror failed.");
940
-      }
941
-  
942
-      return;
943
-  }
944
-  
945
-  sub source_for {
946
-      my($self, $mirror) = @_;
947
-      $mirror =~ s/[^\w\.\-]+/%/g;
948
-  
949
-      my $dir = "$self->{home}/sources/$mirror";
950
-      File::Path::mkpath([ $dir ], 0, 0777);
951
-  
952
-      return $dir;
953
-  }
954
-  
955
-  sub load_argv_from_fh {
956
-      my($self, $fh) = @_;
957
-  
958
-      my @argv;
959
-      while(defined(my $line = <$fh>)){
960
-          chomp $line;
961
-          $line =~ s/#.+$//; # comment
962
-          $line =~ s/^\s+//; # trim spaces
963
-          $line =~ s/\s+$//; # trim spaces
964
-  
965
-          push @argv, split ' ', $line if $line;
966
-      }
967
-      return @argv;
968
-  }
969
-  
970
-  sub show_version {
971
-      print "cpanm (App::cpanminus) version $VERSION\n";
972
-      return 1;
973
-  }
974
-  
975
-  sub show_help {
976
-      my $self = shift;
977
-  
978
-      if ($_[0]) {
979
-          die <<USAGE;
980
-  Usage: cpanm [options] Module [...]
981
-  
982
-  Try `cpanm --help` or `man cpanm` for more options.
983
-  USAGE
984
-      }
985
-  
986
-      print <<HELP;
987
-  Usage: cpanm [options] Module [...]
988
-  
989
-  Options:
990
-    -v,--verbose              Turns on chatty output
991
-    -q,--quiet                Turns off the most output
992
-    --interactive             Turns on interactive configure (required for Task:: modules)
993
-    -f,--force                force install
994
-    -n,--notest               Do not run unit tests
995
-    --test-only               Run tests only, do not install
996
-    -S,--sudo                 sudo to run install commands
997
-    --installdeps             Only install dependencies
998
-    --showdeps                Only display direct dependencies
999
-    --reinstall               Reinstall the distribution even if you already have the latest version installed
1000
-    --mirror                  Specify the base URL for the mirror (e.g. http://cpan.cpantesters.org/)
1001
-    --mirror-only             Use the mirror's index file instead of the CPAN Meta DB
1002
-    --prompt                  Prompt when configure/build/test fails
1003
-    -l,--local-lib            Specify the install base to install modules
1004
-    -L,--local-lib-contained  Specify the install base to install all non-core modules
1005
-    --auto-cleanup            Number of days that cpanm's work directories expire in. Defaults to 7
56
+  Options:
57
+    -v,--verbose              Turns on chatty output
58
+    -q,--quiet                Turns off the most output
59
+    --interactive             Turns on interactive configure (required for Task:: modules)
60
+    -f,--force                force install
61
+    -n,--notest               Do not run unit tests
62
+    --test-only               Run tests only, do not install
63
+    -S,--sudo                 sudo to run install commands
64
+    --installdeps             Only install dependencies
65
+    --showdeps                Only display direct dependencies
66
+    --reinstall               Reinstall the distribution even if you already have the latest version installed
67
+    --mirror                  Specify the base URL for the mirror (e.g. http://cpan.cpantesters.org/)
68
+    --mirror-only             Use the mirror's index file instead of the CPAN Meta DB
69
+    -M,--from                 Use only this mirror base URL and its index file
70
+    --prompt                  Prompt when configure/build/test fails
71
+    -l,--local-lib            Specify the install base to install modules
72
+    -L,--local-lib-contained  Specify the install base to install all non-core modules
73
+    --self-contained          Install all non-core modules, even if they're already installed.
74
+    --auto-cleanup            Number of days that cpanm's work directories expire in. Defaults to 7
1006 75
   
1007 76
   Commands:
1008 77
     --self-upgrade            upgrades itself
1009
-    --info                    Displays distribution info on CPAN
1010
-    --look                    Opens the distribution with your SHELL
1011
-    -V,--version              Displays software version
1012
-  
1013
-  Examples:
1014
-  
1015
-    cpanm Test::More                                          # install Test::More
1016
-    cpanm MIYAGAWA/Plack-0.99_05.tar.gz                       # full distribution path
1017
-    cpanm http://example.org/LDS/CGI.pm-3.20.tar.gz           # install from URL
1018
-    cpanm ~/dists/MyCompany-Enterprise-1.00.tar.gz            # install from a local file
1019
-    cpanm --interactive Task::Kensho                          # Configure interactively
1020
-    cpanm .                                                   # install from local directory
1021
-    cpanm --installdeps .                                     # install all the deps for the current directory
1022
-    cpanm -L extlib Plack                                     # install Plack and all non-core deps into extlib
1023
-    cpanm --mirror http://cpan.cpantesters.org/ DBI           # use the fast-syncing mirror
1024
-  
1025
-  You can also specify the default options in PERL_CPANM_OPT environment variable in the shell rc:
1026
-  
1027
-    export PERL_CPANM_OPT="--prompt --reinstall -l ~/perl --mirror http://cpan.cpantesters.org"
1028
-  
1029
-  Type `man cpanm` or `perldoc cpanm` for the more detailed explanation of the options.
1030
-  
1031
-  HELP
1032
-  
1033
-      return 1;
1034
-  }
1035
-  
1036
-  sub _writable {
1037
-      my $dir = shift;
1038
-      my @dir = File::Spec->splitdir($dir);
1039
-      while (@dir) {
1040
-          $dir = File::Spec->catdir(@dir);
1041
-          if (-e $dir) {
1042
-              return -w _;
1043
-          }
1044
-          pop @dir;
1045
-      }
1046
-  
1047
-      return;
1048
-  }
1049
-  
1050
-  sub maybe_abs {
1051
-      my($self, $lib) = @_;
1052
-      if ($lib eq '_' or $lib =~ /^~/ or File::Spec->file_name_is_absolute($lib)) {
1053
-          return $lib;
1054
-      } else {
1055
-          return File::Spec->canonpath(File::Spec->catdir(Cwd::cwd(), $lib));
1056
-      }
1057
-  }
1058
-  
1059
-  sub bootstrap_local_lib {
1060
-      my $self = shift;
1061
-  
1062
-      # If -l is specified, use that.
1063
-      if ($self->{local_lib}) {
1064
-          return $self->setup_local_lib($self->{local_lib});
1065
-      }
1066
-  
1067
-      # root, locally-installed perl or --sudo: don't care about install_base
1068
-      return if $self->{sudo} or (_writable($Config{installsitelib}) and _writable($Config{installsitebin}));
1069
-  
1070
-      # local::lib is configured in the shell -- yay
1071
-      if ($ENV{PERL_MM_OPT} and ($ENV{MODULEBUILDRC} or $ENV{PERL_MB_OPT})) {
1072
-          $self->bootstrap_local_lib_deps;
1073
-          return;
1074
-      }
1075
-  
1076
-      $self->setup_local_lib;
1077
-  
1078
-      $self->diag(<<DIAG);
1079
-  !
1080
-  ! Can't write to $Config{installsitelib} and $Config{installsitebin}: Installing modules to $ENV{HOME}/perl5
1081
-  ! To turn off this warning, you have to do one of the following:
1082
-  !   - run me as a root or with --sudo option (to install to $Config{installsitelib} and $Config{installsitebin})
1083
-  !   - Configure local::lib your existing local::lib in this shell to set PERL_MM_OPT etc.
1084
-  !   - Install local::lib by running the following commands
1085
-  !
1086
-  !         cpanm --local-lib=~/perl5 local::lib && eval \$(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
1087
-  !
1088
-  DIAG
1089
-      sleep 2;
1090
-  }
1091
-  
1092
-  sub _core_only_inc {
1093
-      my($self, $base) = @_;
1094
-      require local::lib;
1095
-      (
1096
-          local::lib->resolve_path(local::lib->install_base_perl_path($base)),
1097
-          local::lib->resolve_path(local::lib->install_base_arch_path($base)),
1098
-          @Config{qw(privlibexp archlibexp)},
1099
-      );
1100
-  }
1101
-  
1102
-  sub _diff {
1103
-      my($self, $old, $new) = @_;
1104
-  
1105
-      my @diff;
1106
-      my %old = map { $_ => 1 } @$old;
1107
-      for my $n (@$new) {
1108
-          push @diff, $n unless exists $old{$n};
1109
-      }
1110
-  
1111
-      @diff;
1112
-  }
1113
-  
1114
-  sub _setup_local_lib_env {
1115
-      my($self, $base) = @_;
1116
-      local $SIG{__WARN__} = sub { }; # catch 'Attempting to write ...'
1117
-      local::lib->setup_env_hash_for($base);
1118
-  }
1119
-  
1120
-  sub setup_local_lib {
1121
-      my($self, $base) = @_;
1122
-      $base = undef if $base eq '_';
1123
-  
1124
-      require local::lib;
1125
-      {
1126
-          local $0 = 'cpanm'; # so curl/wget | perl works
1127
-          $base ||= "~/perl5";
1128
-          if ($self->{self_contained}) {
1129
-              my @inc = $self->_core_only_inc($base);
1130
-              $self->{search_inc} = [ @inc ];
1131
-          } else {
1132
-              $self->{search_inc} = [
1133
-                  local::lib->resolve_path(local::lib->install_base_arch_path($base)),
1134
-                  local::lib->resolve_path(local::lib->install_base_perl_path($base)),
1135
-                  @INC,
1136
-              ];
1137
-          }
1138
-          $self->_setup_local_lib_env($base);
1139
-      }
1140
-  
1141
-      $self->bootstrap_local_lib_deps;
1142
-  }
1143
-  
1144
-  sub bootstrap_local_lib_deps {
1145
-      my $self = shift;
1146
-      push @{$self->{bootstrap_deps}},
1147
-          'ExtUtils::MakeMaker' => 6.31,
1148
-          'ExtUtils::Install'   => 1.46;
1149
-  }
1150
-  
1151
-  sub prompt_bool {
1152
-      my($self, $mess, $def) = @_;
1153
-  
1154
-      my $val = $self->prompt($mess, $def);
1155
-      return lc $val eq 'y';
1156
-  }
1157
-  
1158
-  sub prompt {
1159
-      my($self, $mess, $def) = @_;
1160
-  
1161
-      my $isa_tty = -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ;
1162
-      my $dispdef = defined $def ? "[$def] " : " ";
1163
-      $def = defined $def ? $def : "";
1164
-  
1165
-      if (!$self->{prompt} || (!$isa_tty && eof STDIN)) {
1166
-          return $def;
1167
-      }
1168
-  
1169
-      local $|=1;
1170
-      local $\;
1171
-      my $ans;
1172
-      eval {
1173
-          local $SIG{ALRM} = sub { undef $ans; die "alarm\n" };
1174
-          print STDOUT "$mess $dispdef";
1175
-          alarm $self->{prompt_timeout} if $self->{prompt_timeout};
1176
-          $ans = <STDIN>;
1177
-          alarm 0;
1178
-      };
1179
-      if ( defined $ans ) {
1180
-          chomp $ans;
1181
-      } else { # user hit ctrl-D or alarm timeout
1182
-          print STDOUT "\n";
1183
-      }
1184
-  
1185
-      return (!defined $ans || $ans eq '') ? $def : $ans;
1186
-  }
1187
-  
1188
-  sub diag_ok {
1189
-      my($self, $msg) = @_;
1190
-      chomp $msg;
1191
-      $msg ||= "OK";
1192
-      if ($self->{in_progress}) {
1193
-          $self->_diag("$msg\n");
1194
-          $self->{in_progress} = 0;
1195
-      }
1196
-      $self->log("-> $msg\n");
1197
-  }
1198
-  
1199
-  sub diag_fail {
1200
-      my($self, $msg, $always) = @_;
1201
-      chomp $msg;
1202
-      if ($self->{in_progress}) {
1203
-          $self->_diag("FAIL\n");
1204
-          $self->{in_progress} = 0;
1205
-      }
1206
-  
1207
-      if ($msg) {
1208
-          $self->_diag("! $msg\n", $always);
1209
-          $self->log("-> FAIL $msg\n");
1210
-      }
1211
-  }
1212
-  
1213
-  sub diag_progress {
1214
-      my($self, $msg) = @_;
1215
-      chomp $msg;
1216
-      $self->{in_progress} = 1;
1217
-      $self->_diag("$msg ... ");
1218
-      $self->log("$msg\n");
1219
-  }
1220
-  
1221
-  sub _diag {
1222
-      my($self, $msg, $always) = @_;
1223
-      print STDERR $msg if $always or $self->{verbose} or !$self->{quiet};
1224
-  }
1225
-  
1226
-  sub diag {
1227
-      my($self, $msg, $always) = @_;
1228
-      $self->_diag($msg, $always);
1229
-      $self->log($msg);
1230
-  }
1231
-  
1232
-  sub chat {
1233
-      my $self = shift;
1234
-      print STDERR @_ if $self->{verbose};
1235
-      $self->log(@_);
1236
-  }
1237
-  
1238
-  sub log {
1239
-      my $self = shift;
1240
-      open my $out, ">>$self->{log}";
1241
-      print $out @_;
1242
-  }
1243
-  
1244
-  sub run {
1245
-      my($self, $cmd) = @_;
1246
-  
1247
-      if (WIN32 && ref $cmd eq 'ARRAY') {
1248
-          $cmd = join q{ }, map { $self->shell_quote($_) } @$cmd;
1249
-      }
1250
-  
1251
-      if (ref $cmd eq 'ARRAY') {
1252
-          my $pid = fork;
1253
-          if ($pid) {
1254
-              waitpid $pid, 0;
1255
-              return !$?;
1256
-          } else {
1257
-              $self->run_exec($cmd);
1258
-          }
1259
-      } else {
1260
-          unless ($self->{verbose}) {
1261
-              $cmd .= " >> " . $self->shell_quote($self->{log}) . " 2>&1";
1262
-          }
1263
-          !system $cmd;
1264
-      }
1265
-  }
1266
-  
1267
-  sub run_exec {
1268
-      my($self, $cmd) = @_;
1269
-  
1270
-      if (ref $cmd eq 'ARRAY') {
1271
-          unless ($self->{verbose}) {
1272
-              open my $logfh, ">>", $self->{log};
1273
-              open STDERR, '>&', $logfh;
1274
-              open STDOUT, '>&', $logfh;
1275
-              close $logfh;
1276
-          }
1277
-          exec @$cmd;
1278
-      } else {
1279
-          unless ($self->{verbose}) {
1280
-              $cmd .= " >> " . $self->shell_quote($self->{log}) . " 2>&1";
1281
-          }
1282
-          exec $cmd;
1283
-      }
1284
-  }
1285
-  
1286
-  sub run_timeout {
1287
-      my($self, $cmd, $timeout) = @_;
1288
-      return $self->run($cmd) if WIN32 || $self->{verbose} || !$timeout;
1289
-  
1290
-      my $pid = fork;
1291
-      if ($pid) {
1292
-          eval {
1293
-              local $SIG{ALRM} = sub { die "alarm\n" };
1294
-              alarm $timeout;
1295
-              waitpid $pid, 0;
1296
-              alarm 0;
1297
-          };
1298
-          if ($@ && $@ eq "alarm\n") {
1299
-              $self->diag_fail("Timed out (> ${timeout}s). Use --verbose to retry.");
1300
-              local $SIG{TERM} = 'IGNORE';
1301
-              kill TERM => 0;
1302
-              waitpid $pid, 0;
1303
-              return;
1304
-          }
1305
-          return !$?;
1306
-      } elsif ($pid == 0) {
1307
-          $self->run_exec($cmd);
1308
-      } else {
1309
-          $self->chat("! fork failed: falling back to system()\n");
1310
-          $self->run($cmd);
1311
-      }
1312
-  }
1313
-  
1314
-  sub configure {
1315
-      my($self, $cmd) = @_;
1316
-  
1317
-      # trick AutoInstall
1318
-      local $ENV{PERL5_CPAN_IS_RUNNING} = local $ENV{PERL5_CPANPLUS_IS_RUNNING} = $$;
1319
-  
1320
-      # e.g. skip CPAN configuration on local::lib
1321
-      local $ENV{PERL5_CPANM_IS_RUNNING} = $$;
1322
-  
1323
-      my $use_default = !$self->{interactive};
1324
-      local $ENV{PERL_MM_USE_DEFAULT} = $use_default;
1325
-  
1326
-      # skip man page generation
1327
-      local $ENV{PERL_MM_OPT} = $ENV{PERL_MM_OPT};
1328
-      unless ($self->{pod2man}) {
1329
-          $ENV{PERL_MM_OPT} .= " INSTALLMAN1DIR=none INSTALLMAN3DIR=none";
1330
-      }
1331
-  
1332
-      local $self->{verbose} = $self->{verbose} || $self->{interactive};
1333
-      $self->run_timeout($cmd, $self->{configure_timeout});
1334
-  }
1335
-  
1336
-  sub build {
1337
-      my($self, $cmd, $distname) = @_;
1338
-  
1339
-      return 1 if $self->run_timeout($cmd, $self->{build_timeout});
1340
-      while (1) {
1341
-          my $ans = lc $self->prompt("Building $distname failed.\nYou can s)kip, r)etry, e)xamine build log, or l)ook ?", "s");
1342
-          return                               if $ans eq 's';
1343
-          return $self->build($cmd, $distname) if $ans eq 'r';
1344
-          $self->show_build_log                if $ans eq 'e';
1345
-          $self->look                          if $ans eq 'l';
1346
-      }
1347
-  }
1348
-  
1349
-  sub test {
1350
-      my($self, $cmd, $distname) = @_;
1351
-      return 1 if $self->{notest};
1352
-  
1353
-      # https://rt.cpan.org/Ticket/Display.html?id=48965#txn-1013385
1354
-      local $ENV{PERL_MM_USE_DEFAULT} = 1;
1355
-  
1356
-      return 1 if $self->run_timeout($cmd, $self->{test_timeout});
1357
-      if ($self->{force}) {
1358
-          $self->diag_fail("Testing $distname failed but installing it anyway.");
1359
-          return 1;
1360
-      } else {
1361
-          $self->diag_fail;
1362
-          while (1) {
1363
-              my $ans = lc $self->prompt("Testing $distname failed.\nYou can s)kip, r)etry, f)orce install, e)xamine build log, or l)ook ?", "s");
1364
-              return                              if $ans eq 's';
1365
-              return $self->test($cmd, $distname) if $ans eq 'r';
1366
-              return 1                            if $ans eq 'f';
1367
-              $self->show_build_log               if $ans eq 'e';
1368
-              $self->look                         if $ans eq 'l';
1369
-          }
1370
-      }
1371
-  }
1372
-  
1373
-  sub install {
1374
-      my($self, $cmd, $uninst_opts, $depth) = @_;
1375
-  
1376
-      if ($depth == 0 && $self->{test_only}) {
1377
-          return 1;
1378
-      }
1379
-  
1380
-      if ($self->{sudo}) {
1381
-          unshift @$cmd, "sudo";
1382
-      }
1383
-  
1384
-      if ($self->{uninstall_shadows} && !$ENV{PERL_MM_OPT}) {
1385
-          push @$cmd, @$uninst_opts;
1386
-      }
1387
-  
1388
-      $self->run($cmd);
1389
-  }
1390
-  
1391
-  sub look {
1392
-      my $self = shift;
1393
-  
1394
-      my $shell = $ENV{SHELL};
1395
-      $shell  ||= $ENV{COMSPEC} if WIN32;
1396
-      if ($shell) {
1397
-          my $cwd = Cwd::cwd;
1398
-          $self->diag("Entering $cwd with $shell\n");
1399
-          system $shell;
1400
-      } else {
1401
-          $self->diag_fail("You don't seem to have a SHELL :/");
1402
-      }
1403
-  }
1404
-  
1405
-  sub show_build_log {
1406
-      my $self = shift;
1407
-  
1408
-      my @pagers = (
1409
-          $ENV{PAGER},
1410
-          (WIN32 ? () : ('less')),
1411
-          'more'
1412
-      );
1413
-      my $pager;
1414
-      while (@pagers) {
1415
-          $pager = shift @pagers;
1416
-          next unless $pager;
1417
-          $pager = $self->which($pager);
1418
-          next unless $pager;
1419
-          last;
1420
-      }
1421
-  
1422
-      if ($pager) {
1423
-          # win32 'more' doesn't allow "more build.log", the < is required
1424
-          system("$pager < $self->{log}");
1425
-      }
1426
-      else {
1427
-          $self->diag_fail("You don't seem to have a PAGER :/");
1428
-      }
1429
-  }
1430
-  
1431
-  sub chdir {
1432
-      my $self = shift;
1433
-      Cwd::chdir(File::Spec->canonpath($_[0])) or die "$_[0]: $!";
1434
-  }
1435
-  
1436
-  sub configure_mirrors {
1437
-      my $self = shift;
1438
-      unless (@{$self->{mirrors}}) {
1439
-          $self->{mirrors} = [ 'http://www.cpan.org' ];
1440
-      }
1441
-      for (@{$self->{mirrors}}) {
1442
-          s!^/!file:///!;
1443
-          s!/$!!;
1444
-      }
1445
-  }
1446
-  
1447
-  sub self_upgrade {
1448
-      my $self = shift;
1449
-      $self->{argv} = [ 'App::cpanminus' ];
1450
-      return; # continue
1451
-  }
1452
-  
1453
-  sub install_module {
1454
-      my($self, $module, $depth, $version) = @_;
1455
-  
1456
-      if ($self->{seen}{$module}++) {
1457
-          $self->chat("Already tried $module. Skipping.\n");
1458
-          return 1;
1459
-      }
1460
-  
1461
-      my $dist = $self->resolve_name($module, $version);
1462
-      unless ($dist) {
1463
-          $self->diag_fail("Couldn't find module or a distribution $module ($version)", 1);
1464
-          return;
1465
-      }
1466
-  
1467
-      if ($dist->{distvname} && $self->{seen}{$dist->{distvname}}++) {
1468
-          $self->chat("Already tried $dist->{distvname}. Skipping.\n");
1469
-          return 1;
1470
-      }
1471
-  
1472
-      if ($self->{cmd} eq 'info') {
1473
-          print $self->format_dist($dist), "\n";
1474
-          return 1;
1475
-      }
1476
-  
1477
-      $self->check_libs;
1478
-      $self->setup_module_build_patch unless $self->{pod2man};
1479
-  
1480
-      if ($dist->{module}) {
1481
-          unless ($self->with_version_range($version)) {
1482
-              my($ok, $local) = $self->check_module($dist->{module}, $dist->{module_version} || 0);
1483
-              if ($self->{skip_installed} && $ok) {
1484
-                  $self->diag("$dist->{module} is up to date. ($local)\n", 1);
1485
-                  return 1;
1486
-              }
1487
-          }
1488
-  
1489
-          unless ($self->satisfy_version($dist->{module}, $dist->{module_version}, $version)) {
1490
-              $self->diag("Found $dist->{module} $dist->{module_version} which doesn't satisfy $version.\n");
1491
-              return;
1492
-          }
1493
-      }
1494
-  
1495
-      if ($dist->{dist} eq 'perl'){
1496
-          $self->diag("skipping $dist->{pathname}\n");
1497
-          return 1;
1498
-      }
1499
-  
1500
-      $self->diag("--> Working on $module\n");
1501
-  
1502
-      $dist->{dir} ||= $self->fetch_module($dist);
1503
-  
1504
-      unless ($dist->{dir}) {
1505
-          $self->diag_fail("Failed to fetch distribution $dist->{distvname}", 1);
1506
-          return;
1507
-      }
1508
-  
1509
-      $self->chat("Entering $dist->{dir}\n");
1510
-      $self->chdir($self->{base});
1511
-      $self->chdir($dist->{dir});
1512
-  
1513
-      if ($self->{cmd} eq 'look') {
1514
-          $self->look;
1515
-          return 1;
1516
-      }
1517
-  
1518
-      return $self->build_stuff($module, $dist, $depth);
1519
-  }
1520
-  
1521
-  sub format_dist {
1522
-      my($self, $dist) = @_;
1523
-  
1524
-      # TODO support --dist-format?
1525
-      return "$dist->{cpanid}/$dist->{filename}";
1526
-  }
1527