File Coverage

blib/lib/PAR/Heavy.pm
Criterion Covered Total %
statement 28 87 32.1
branch 4 56 7.1
condition 0 15 0.0
subroutine 5 9 55.5
pod n/a
total 37 167 22.1


line stmt bran cond sub pod time code
1             package PAR::Heavy;
2 4     4   36 use strict;
  4         8  
  4         168  
3 4     4   21 use warnings;
  4         9  
  4         1245  
4              
5             $PAR::Heavy::VERSION = '0.12';
6              
7             =head1 NAME
8              
9             PAR::Heavy - PAR guts
10              
11             =head1 SYNOPSIS
12              
13             (internal use only)
14              
15             =head1 DESCRIPTION
16              
17             No user-serviceable parts inside.
18              
19             =cut
20              
21             ########################################################################
22             # Dynamic inclusion of XS modules
23              
24             # NOTE: Don't "use" any module here, esp. one that is an XS module or
25             # whose "use" could cause the loading of an XS module thru its dependencies.
26              
27             # enable debug/trace messages from DynaLoader perl code
28             my $dl_debug = $ENV{PERL_DL_DEBUG} || 0;
29              
30             our %FullCache;
31              
32             my ($bootstrap, $dl_findfile); # Caches for code references
33             my ($cache_key); # The current file to find
34             my $is_insensitive_fs = (
35             -s $0
36             and (-s lc($0) || -1) == (-s uc($0) || -1)
37             and (-s lc($0) || -1) == -s $0
38             );
39              
40             # Adds pre-hooks to Dynaloader's key methods
41             sub _init_dynaloader {
42 7 100   7   26 return if $bootstrap;
43 4 50       7 return unless eval { require DynaLoader; DynaLoader::dl_findfile(); 1 };
  4         30  
  4         46  
  4         12  
44              
45 4 50       14 print STDERR "PAR::Heavy: pre-hooks to Dynaloader's key methods\n"
46             if $dl_debug;
47              
48 4         11 $bootstrap = \&DynaLoader::bootstrap;
49 4         10 $dl_findfile = \&DynaLoader::dl_findfile;
50              
51             {
52 4     4   7 no strict 'refs';
  4         35  
  4         7  
  4         243  
53 4         47 local $^W;
54 4     4   21 no warnings 'redefine';
  4         7  
  4         5429  
55 4     0   20 *{'DynaLoader::dl_expandspec'} = sub { return };
  4         144  
  0         0  
56 4         14 *{'DynaLoader::bootstrap'} = \&_bootstrap;
  4         18  
57 4         9 *{'DynaLoader::dl_findfile'} = \&_dl_findfile;
  4         22  
58             }
59             }
60              
61             # Return the cached location of .dll inside PAR first, if possible.
62             sub _dl_findfile {
63 0 0   0   0 print STDERR "PAR::Heavy::_dl_findfile($cache_key)\n" if $dl_debug;
64              
65 0 0       0 if (exists $FullCache{$cache_key}) {
66 0 0       0 print STDERR " found in FullCache as $FullCache{$cache_key}\n"
67             if $dl_debug;
68 0         0 return $FullCache{$cache_key};
69             }
70 0 0       0 if ($is_insensitive_fs) {
71             # We have a case-insensitive filesystem...
72 0         0 my ($key) = grep { lc($_) eq lc($cache_key) } keys %FullCache;
  0         0  
73 0 0       0 if (defined $key) {
74 0 0       0 print STDERR " found case-insensitively in FullCache as $FullCache{$key}\n"
75             if $dl_debug;
76 0         0 return $FullCache{$key};
77             }
78             }
79 0 0       0 print STDERR " fall back to DynaLoader::dl_findfile\n" if $dl_debug;
80 0         0 return $dl_findfile->(@_);
81             }
82              
83             # Find and extract .dll from PAR files for a given dynamic module.
84             sub _bootstrap {
85 0     0   0 my (@args) = @_;
86 0 0       0 my ($module) = $args[0] or return;
87              
88 0         0 my @modparts = split(/::/, $module);
89 0         0 my $modfname = $modparts[-1];
90              
91 0 0       0 $modfname = &DynaLoader::mod2fname(\@modparts)
92             if defined &DynaLoader::mod2fname;
93              
94 0 0 0     0 if (($^O eq 'NetWare') && (length($modfname) > 8)) {
95 0         0 $modfname = substr($modfname, 0, 8);
96             }
97              
98 0 0       0 my $modpname = join((($^O eq 'MacOS') ? ':' : '/'), @modparts);
99 0         0 my $file = $cache_key = "auto/$modpname/$modfname.$DynaLoader::dl_dlext";
100              
101 0 0       0 if ($FullCache{$file}) {
102             # TODO: understand
103 0         0 local $DynaLoader::do_expand = 1;
104 0         0 return $bootstrap->(@args);
105             }
106              
107 0         0 my $member;
108             # First, try to find things in the preferentially loaded PARs:
109 0 0       0 $member = PAR::_find_par_internals([@PAR::PAR_INC], undef, $file, 1)
110             if defined &PAR::_find_par_internals;
111              
112             # If that failed to find the dll, let DynaLoader (try or) throw an error
113 0 0       0 unless ($member) {
114 0         0 my $filename = eval { $bootstrap->(@args) };
  0         0  
115 0 0 0     0 return $filename if not $@ and defined $filename;
116              
117             # Now try the fallback pars
118 0 0       0 $member = PAR::_find_par_internals([@PAR::PAR_INC_LAST], undef, $file, 1)
119             if defined &PAR::_find_par_internals;
120              
121             # If that fails, let dynaloader have another go JUST to throw an error
122             # While this may seem wasteful, nothing really matters once we fail to
123             # load shared libraries!
124 0 0       0 unless ($member) {
125 0         0 return $bootstrap->(@args);
126             }
127             }
128              
129 0         0 $FullCache{$file} = _dl_extract($member);
130              
131             # Now extract all associated shared objs in the same auto/ dir
132             # XXX: shouldn't this also set $FullCache{...} for those files?
133 0         0 my $first = $member->fileName;
134 0         0 my $path_pattern = $first;
135 0         0 $path_pattern =~ s{[^/]*$}{};
136 0 0       0 if ($PAR::LastAccessedPAR) {
137 0         0 foreach my $member ( $PAR::LastAccessedPAR->members ) {
138 0 0       0 next if $member->isDirectory;
139              
140 0         0 my $name = $member->fileName;
141 0 0       0 next if $name eq $first;
142 0 0       0 next unless $name =~ m{^/?\Q$path_pattern\E\/[^/]*\.\Q$DynaLoader::dl_dlext\E[^/]*$};
143 0         0 $name =~ s{.*/}{};
144 0         0 _dl_extract($member, $name);
145             }
146             }
147              
148 0         0 local $DynaLoader::do_expand = 1;
149 0         0 return $bootstrap->(@args);
150             }
151              
152             sub _dl_extract {
153 0     0   0 my ($member, $name) = @_;
154 0   0     0 $name ||= $member->crc32String . ".$DynaLoader::dl_dlext";
155              
156 0   0     0 my $filename = File::Spec->catfile($ENV{PAR_TEMP} || File::Spec->tmpdir, $name);
157 0         0 ($filename) = $filename =~ /^([\x20-\xff]+)$/;
158              
159 0 0 0     0 return $filename if -e $filename && -s _ == $member->uncompressedSize;
160              
161             # $filename doesn't exist or hasn't been completely extracted:
162             # extract it under a temporary name that isn't likely to be used
163             # by concurrent processes doing the same
164 0         0 my $tempname = "$filename.$$";
165 0 0       0 $member->extractToFileNamed($tempname) == Archive::Zip::AZ_OK()
166             or die "Can't extract archive member ".$member->fileName." to $tempname: $!";
167              
168             # now that we have a "good" copy in $tempname, rename it to $filename;
169             # if this fails (e.g. some OSes won't let you delete DLLs that are
170             # in use), but $filename exists, we assume that $filename is also
171             # "good": remove $tempname and return $filename
172 0 0       0 unless (rename($tempname, $filename))
173             {
174 0 0       0 -e $filename or die "can't rename $tempname to $filename: $!";
175 0         0 unlink($tempname);
176             }
177 0         0 return $filename;
178             }
179              
180             1;
181              
182             =head1 SEE ALSO
183              
184             L
185              
186             =head1 AUTHORS
187              
188             Audrey Tang Ecpan@audreyt.orgE
189              
190             You can write
191             to the mailing list at Epar@perl.orgE, or send an empty mail to
192             Epar-subscribe@perl.orgE to participate in the discussion.
193             Archives of the mailing list are available at
194             Ehttps://www.mail-archive.com/par@perl.org/E or Ehttps://groups.google.com/g/perl.parE.
195              
196             Please submit bug reports to Ehttps://github.com/rschupp/PAR/issuesE.
197              
198             =head1 COPYRIGHT
199              
200             Copyright 2002-2010 by Audrey Tang
201             Ecpan@audreyt.orgE.
202              
203             Copyright 2006-2010 by Steffen Mueller
204             Esmueller@cpan.orgE.
205              
206             This program is free software; you can redistribute it and/or modify it
207             under the same terms as Perl itself.
208              
209             See F.
210              
211             =cut