|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package lib::archive;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
411061
 | 
 use strict;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
154
 | 
    | 
| 
4
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
28
 | 
 use warnings;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
130
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
108
 | 
 use 5.010001;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
26
 | 
 use Carp qw(croak);  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
300
 | 
    | 
| 
9
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
3680
 | 
 use Archive::Tar;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
480152
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
398
 | 
    | 
| 
10
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
2690
 | 
 use File::Spec::Functions qw(file_name_is_absolute rel2abs);  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4278
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
380
 | 
    | 
| 
11
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
36
 | 
 use File::Basename qw(basename dirname fileparse);  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
491
 | 
    | 
| 
12
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
37
 | 
 use File::Path qw(make_path);  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
267
 | 
    | 
| 
13
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
2305
 | 
 use MIME::Base64 qw(decode_base64);  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3523
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
292
 | 
    | 
| 
14
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
57
 | 
 use IO::Uncompress::Gunzip;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
181
 | 
    | 
| 
15
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
3019
 | 
 use HTTP::Tiny;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
183451
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7264
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = "0.92";  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =pod  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 lib::archive - load pure-Perl modules directly from TAR archives  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use lib::archive ("../external/*.tgz", "lib/extra.tar");  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use MyModule; # the given tar archives will be searched first  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use lib::archive qw(  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     https://www.cpan.org/modules/by-module/JSON/JSON-PP-2.97001.tar.gz  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     CPAN://YAML-PP-0.007.tar.gz  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use JSON::PP;  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use YAML::PP;  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use lib::archive '__DATA__';  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   __DATA__  | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Specify TAR archives to directly load modules from. The TAR files will be  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 searched like include dirs. Globs are expanded, so you can use wildcards  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 (not for URLs). If modules are present in more than one TAR archive, the  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 first one will be used.  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Relative paths will be interpreted as relative to the directory the  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 calling script or module resides in. So don't do a chdir() before using  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 lib::archive when you call your script with a relative path B use releative  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 paths for lib::archive.  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 B
 | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Everything is extracted on the fly>. When running under a debugger or the  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 environment variable PERL_LIB_ARCHIVE_EXTRACT is set to a directory name  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the directories and files will be extracted to the filesystem. I case of  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 running under a debugger without PERL_LIB_ARCHIVE_EXTRACT being set the  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 extracted modules will be  saved to the .lib_archive_extract directory  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 in the user's home directory (determined by C). The home  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 directory can be overwritten by setting the environment variable  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 PERL_LIB_ARCHIVE_HOME.  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 An attempt will be made to create the directory should it not already exist.  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 You can use every file format Archive::Tar supports.  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If the archive contains a toplevel directory 'lib' the module search path  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 will start there. Otherwise it will start from the root of the archive.  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If the archive is a gzipped TAR archive with the extension '.tar.gz' and the  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 archive contains a toplevel directory matching the archive name without the  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 extension the module search path starts with this directory. The above  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 rule for the subdirectory 'lib' applies from there. This means that e.g. for  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 'JSON-PP-2.97001.tar.gz' the modules will only be included from  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 'JSON-PP-2.97001/lib'.  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 You can use URLs for loading modules directly from CPAN. Either specify the  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 complete URL like:  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use lib::archive 'https://www.cpan.org/modules/by-module/JSON/JSON-PP-2.97001.tar.gz';  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or use a shortcut like:  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use lib::archive 'CPAN://JSON-PP-2.97001.tar.gz';  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 which will do exactly the same thing (at least in most cases: there seem to  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 be modules without an entry under 'modules/by-module/'; in that  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 case you have to use an URL pointing to the file under 'authors/id').  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If the environment variable CPAN_MIRROR is set, it will be used instead of  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 'https://www.cpan.org'.  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 WHY  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 There are two use cases that motivated the creation of this module:  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item 1. bundling various self written modules as a versioned release  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item 2. quickly switching between different versions of a module for debugging purposes  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 AUTHOR  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Thomas Kratz Etomk@cpan.orgE  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $cpan   = $ENV{CPAN_MIRROR} || 'https://www.cpan.org';  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $rx_url = qr!^(?:CPAN|https?)://!;  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $tar    = Archive::Tar->new();  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $home   = $ENV{PERL_LIB_ARCHIVE_HOME} // glob('~');  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub import {  | 
| 
125
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
67
 | 
     my ( $class, @entries ) = @_;  | 
| 
126
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my %cache;  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
128
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     my $caller_file    = (caller)[1];  | 
| 
129
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     my $under_debugger = defined($DB::single);  | 
| 
130
 | 
6
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
35
 | 
     my $extract_dir    = $ENV{PERL_LIB_ARCHIVE_EXTRACT} // "$home/.lib_archive_extract";  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
132
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     for my $entry (@entries) {  | 
| 
133
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
         my $is_url = $entry =~ /$rx_url/;  | 
| 
134
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
43
 | 
         my $arcs  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             = $is_url                  ? _get_url($entry)  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             : ( $entry eq '__DATA__' ) ? _get_data($caller_file)  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             :                            _get_files( $entry, $caller_file );  | 
| 
138
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
         for my $arc (@$arcs) {  | 
| 
139
 | 
15
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
             my $path = $is_url ? $entry : $arc->[0];  | 
| 
140
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
540
 | 
             my $base = basename($path);  | 
| 
141
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
96
 | 
             my @ver  = $base =~ /(v?\d+\.\d+(?:\.\d+)?)/gi;  | 
| 
142
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
             my %tmp;  | 
| 
143
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
             my $mod = 0;  | 
| 
144
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
             my $lib = 0;  | 
| 
145
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
             for my $f ( $tar->read( $arc->[0] ) ) {  | 
| 
146
 | 
75
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
67862
 | 
                 next unless ( my $full = $f->full_path ) =~ /\.pm$/;  | 
| 
147
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
922
 | 
                 my @parts = split( '/', $full );  | 
| 
148
 | 
36
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
90
 | 
                 ++$mod && shift @parts if $parts[0] eq $arc->[1];  | 
| 
149
 | 
36
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
79
 | 
                 ++$lib && shift @parts if $parts[0] eq 'lib';  | 
| 
150
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
                 my $rel = join( '/', @parts );  | 
| 
151
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
                 $tmp{$rel}{$full} = $f->get_content_by_ref;  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
153
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
158
 | 
             for my $rel ( keys %tmp ) {  | 
| 
154
 | 
23
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
72
 | 
                 my $full = join( '/', $mod ? $arc->[1] : (), $lib ? 'lib' : (), $rel );  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
155
 | 
23
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
211
 | 
                 $cache{$rel} //= { path => "$path/$full", content => $tmp{$rel}{$full}, arcver => $ver[-1] // '' };  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     unshift @INC, sub {  | 
| 
161
 | 
47
 | 
 
 | 
 
 | 
  
47
  
 | 
 
 | 
425469
 | 
         my ( $cref, $rel ) = @_;  | 
| 
162
 | 
47
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
17322
 | 
         return unless my $rec = $cache{$rel};  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $INC{$rel} = _expand( $rel, $rec->{content}, $rec->{arcver}, $extract_dir )  | 
| 
164
 | 
14
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
101
 | 
             if $ENV{PERL_LIB_ARCHIVE_EXTRACT} or $under_debugger;  | 
| 
165
 | 
14
 | 
  
 50
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
47
 | 
         $INC{$rel} //= $rec->{path} unless $under_debugger;  | 
| 
166
 | 
6
 | 
  
 50
  
 | 
 
 | 
  
6
  
 | 
 
 | 
38
 | 
         open( my $pfh, '<', $rec->{content} ) or croak $!;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
    | 
| 
 
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
259
 | 
    | 
| 
167
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4991
 | 
         return $pfh;  | 
| 
168
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
106
 | 
     };  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
170
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3398
 | 
     return;  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_files {  | 
| 
175
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
 
 | 
13
 | 
     my ( $glob, $cfile ) = @_;  | 
| 
176
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     ( my $glob_ux = $glob )                      =~ s!\\!/!g;  | 
| 
177
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     ( my $cdir    = dirname( rel2abs($cfile) ) ) =~ s!\\!/!g;  | 
| 
178
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
533
 | 
     $glob_ux = "$cdir/$glob_ux" unless file_name_is_absolute($glob_ux);  | 
| 
179
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
     my @files;  | 
| 
180
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
354
 | 
     for my $f ( sort glob($glob_ux) ) {  | 
| 
181
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
277
 | 
         my ( $module, $dirs, $suffix ) = fileparse( $f, qr/\.tar\.gz/ );  | 
| 
182
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
         push @files, [ $f, $module ];  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
184
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     return \@files;  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_url {  | 
| 
189
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
4
 | 
     my ($url) = @_;  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
191
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my ($module) = $url =~ m!/([^/]+)\.tar\.gz$!;  | 
| 
192
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     my ($top)    = split( /-/, $module );  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
194
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     $url =~ s!^CPAN://!$cpan/modules/by-module/$top/!;  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
196
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     my $rp = HTTP::Tiny->new->get($url);  | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
198
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
338936
 | 
     my @zips;  | 
| 
199
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
737
 | 
     if ( $rp->{success} ) {  | 
| 
200
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
         my $z = IO::Uncompress::Gunzip->new( \$rp->{content} );  | 
| 
201
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4185
 | 
         push @zips, [ $z, $module ];  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else {  | 
| 
204
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         croak "GET '$url' failed with status:", $rp->{status};  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
206
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     return \@zips;  | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _get_data {  | 
| 
211
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
2
 | 
     my ($cfn) = @_;  | 
| 
212
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
55
 | 
     open( my $fh, '<', $cfn ) or croak "couldn't open $cfn, $!";  | 
| 
213
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     local $/ = undef;  | 
| 
214
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     my $data = <$fh>;  | 
| 
215
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     close($fh);  | 
| 
216
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
     $data =~ s/^.*\n__DATA__\r?\n/\n/s;  | 
| 
217
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     my @data = split( /\n\n+/, $data );  | 
| 
218
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my @tars;  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     for my $d (@data) {  | 
| 
221
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
         my $content = decode_base64($d);  | 
| 
222
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
         my $z       = eval { IO::Uncompress::Gunzip->new( \$content ) };  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
223
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
2716
 | 
         if ($z) {  | 
| 
224
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             push @tars, [ $z, '' ];  | 
| 
225
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             next;  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
227
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         open( my $cfh, '<', \$content ) or croak $!;    ## no critic (RequireBriefOpen)  | 
| 
228
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         push @tars, [ $cfh, '' ];  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
230
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     return \@tars;  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _expand {  | 
| 
235
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
48
 | 
     my ( $rel, $cref, $ver, $exdir ) = @_;  | 
| 
236
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
57
 | 
     my $fn = $ver ? "$exdir/$ver/$rel" : "$exdir/$rel";  | 
| 
237
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2298
 | 
     make_path( dirname($fn) );  | 
| 
238
 | 
14
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1027
 | 
     open( my $fh, '>', $fn ) or die "couldn't save $fn, $!\n";  | 
| 
239
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
248
 | 
     print $fh $$cref;  | 
| 
240
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
703
 | 
     close($fh);  | 
| 
241
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
102
 | 
     return $fn;  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  |