File Coverage

lib/ExtUtils/InferConfig.pm
Criterion Covered Total %
statement 91 102 89.2
branch 22 46 47.8
condition 3 12 25.0
subroutine 12 12 100.0
pod 3 3 100.0
total 131 175 74.8


line stmt bran cond sub pod time code
1             package ExtUtils::InferConfig;
2              
3 2     2   209403 use strict;
  2         5  
  2         61  
4 2     2   20 use Config;
  2         4  
  2         79  
5 2     2   12 use Carp qw/croak/;
  2         2  
  2         130  
6 2     2   2252 use IPC::Cmd qw//;
  2         149896  
  2         82  
7              
8 2     2   24 use vars qw/$VERSION/;
  2         5  
  2         115  
9             BEGIN {
10 2     2   2878 $VERSION = '1.04';
11             }
12              
13             #use constant ISWIN32 => ($^O =~ /win32/i ? 1 : 0);
14              
15             =head1 NAME
16              
17             ExtUtils::InferConfig - Infer Perl Configuration for non-running interpreters
18              
19             =head1 SYNOPSIS
20              
21             use ExtUtils::InferConfig;
22             my $eic = ExtUtils::InferConfig->new(
23             perl => '/path/to/a/perl'
24             );
25            
26             # Get that interpreters %Config as hash ref
27             my $Config = $eic->get_config;
28            
29             # Get that interpreters @INC as array ref
30             my $INC = $eic->get_inc;
31              
32             =head1 DESCRIPTION
33              
34             This module can determine the configuration and C<@INC> of a perl
35             interpreter given its path and that it is runnable by the current
36             user.
37              
38             It runs the interpreter with a one-liner and grabs the C<%Config>
39             hash via STDOUT capturing. Getting the module load paths, C<@INC>,
40             works the same way for C<@INC> entries that are plain paths.
41              
42             =head1 METHODS
43              
44             =head2 new
45              
46             Requires one named parameter: C, the path to the perl
47             interpreter to query for information.
48              
49             Optional parameter: C 1> enables the debugging mode.
50              
51             =cut
52              
53             sub new {
54 2     2 1 1791 my $class = shift;
55 2   33     19 $class = ref($class) || $class;
56              
57 2         8 my %args = @_;
58              
59              
60 2 50       87 my $self = {
61             perl => undef,
62             config => undef,
63             inc => undef,
64             ($args{debug} ? (debug => 1) : ()),
65             };
66 2         11 bless $self => $class;
67              
68             # get interpreter, check that we have access
69 2   33     9 my $perl = $args{perl} || $^X;
70 2         8 $perl = $self->_perl_to_file($perl);
71              
72 2 50       9 if (not defined $perl) {
73 0         0 croak(
74             "Invalid perl interpreter specified. "
75             ."It was either not found or it is not executable."
76             );
77             }
78              
79 2 50       17 warn "Using perl '$perl'" if $self->{debug};
80              
81 2         5 $self->{perl} = $perl;
82              
83 2         8 return $self;
84             }
85              
86             sub _perl_to_file {
87             # see perldoc perlvar about this. Look for $^X
88 2     2   3 my $self = shift;
89 2         5 my $perl = shift;
90              
91 2 50       13 return() if not defined $perl;
92 2 50 33     137 return $perl if -f $perl and -x _;
93              
94             # Build up a set of file names (not command names).
95 0 0       0 if ($^O ne 'VMS') {
96 0 0       0 $perl .= $Config{_exe}
97             unless $perl =~ m/\Q$Config{_exe}$/i;
98             }
99              
100 0 0 0     0 return $perl if -f $perl and -x _;
101 0         0 return();
102             }
103              
104              
105             =head2 get_config
106              
107             Returns a copy of the C<%Config::Config> hash of the
108             intepreter which was specified as a parameter to the
109             constructor.
110              
111             The first time this method (or the get_inc method below)
112             is called, the perl binary is run. For subsequent calls
113             of this method, the information is cached.
114              
115             =cut
116              
117             sub get_config {
118 1     1 1 498 my $self = shift;
119 1 50       4 return $self->{config} if defined $self->{config};
120              
121 1         3 $self->{config} = $self->_infer_config($self->{perl});
122              
123 1         10 return $self->{config};
124             }
125              
126             sub _infer_config {
127 1     1   1 my $self = shift;
128 1         2 my $perl = shift;
129 1         1 my $code = <<'HERE';
130             use Config;
131             foreach my $k (keys %Config) {
132             my $ek = $k;
133             $ek =~ s/([\n\t\r%])/q{%}.ord($1).q{;}/ge;
134             my $ev = $Config{$k};
135             if (defined $ev) {
136             $ev =~ s/([\n\t\r%])/q{%}.ord($1).q{;}/ge;
137             } else {
138             $ev = q{%-1;};
139             }
140             print qq{$ek\n$ev\n};
141             }
142             HERE
143              
144 1 50       4 warn "Running the following code:\n---$code\n---" if $self->{debug};
145              
146 1         10 $code =~ s/\s+$//;
147 1         6 $code =~ s/\n/ /g;
148              
149 1         3 my @command = (
150             $perl, '-e', $code
151             );
152 1 50       3 warn "Running the following command: '@command'" if $self->{debug};
153              
154 1         2 my $old_use_run = $IPC::Cmd::USE_IPC_RUN;
155 1         2 $IPC::Cmd::USE_IPC_RUN = 1;
156 1         4 my ($success, $error_code, undef, $buffer, $error) = IPC::Cmd::run(
157             command => \@command,
158             );
159 1         171713 $IPC::Cmd::USE_IPC_RUN = $old_use_run;
160            
161              
162 1 50       18 warn "Returned buffer is:\n---\n".join("\n",@$buffer)."\n---" if $self->{debug};
163 1 50       14 warn "Returned error buffer is:\n---\n".join("\n",@$error)."\n---" if $self->{debug};
164              
165 1 50       8 if (not $success) {
166 0         0 croak(
167             "Could not run the specified perl interpreter to determine \%Config. Error code (if any) was: $error_code. STDERR was (if any): ".join('', @$error)
168             );
169             }
170              
171 1         2 my %Config;
172 1         1051 my @data = split /\n/, join '', @$buffer;
173 1         69 while (@data) {
174 1119         1709 my $key = shift(@data);
175 1119         1214 chomp $key;
176 1119         2684 my $value = shift(@data);
177 1119 100       2187 $value = '' if !defined $value; #in case of last value
178 1119         1069 chomp $value;
179 1119         5265 $key =~ s/%(\d+);/chr($1)/eg;
  0         0  
180 1119 100       1713 if ($value eq '%-1;') {
181 198         212 $value = undef;
182             }
183             else {
184 921         1045 $value =~ s/%(\d+);/chr($1)/eg;
  0         0  
185             }
186 1119         3879 $Config{$key} = $value;
187             }
188              
189 1         15 return \%Config;
190             }
191              
192              
193             =head2 get_inc
194              
195             Returns a copy of the C<@INC> array of the
196             intepreter which was specified as a parameter to the
197             constructor. B This skips any references
198             (subroutines, C refs, objects) in the C<@INC>
199             array because they cannot be reliably stringified!
200              
201             The first time this method (or the get_config method avove)
202             is called, the perl binary is run. For subsequent calls
203             of this method, the information is cached.
204              
205             =cut
206              
207             sub get_inc {
208 1     1 1 512 my $self = shift;
209 1 50       6 return $self->{config} if defined $self->{inc};
210              
211 1         3 $self->{inc} = $self->_infer_inc($self->{perl});
212              
213 1         68 return $self->{inc};
214             }
215              
216              
217             sub _infer_inc {
218 1     1   3 my $self = shift;
219 1         1 my $perl = shift;
220 1         2 my $code = <<'HERE';
221             foreach my $inc (@INC) {
222             my $i = $inc;
223             if (not ref($i)) {
224             $i =~ s/([\n\t\r%])/q{%}.ord($1).q{;}/ge;
225             }
226             print qq{$i\n};
227             }
228             HERE
229 1 50       5 warn "Running the following code:\n---$code\n---" if $self->{debug};
230              
231 1         9 $code =~ s/\s+$//;
232 1         7 $code =~ s/\n/ /g;
233              
234 1         3 my @command = (
235             $perl, '-e', $code
236             );
237 1 50       3 warn "Running the following command: '@command'" if $self->{debug};
238              
239 1         2 my $old_use_run = $IPC::Cmd::USE_IPC_RUN;
240 1         2 $IPC::Cmd::USE_IPC_RUN = 1;
241 1         5 my ($success, $error_code, undef, $buffer, $error) = IPC::Cmd::run(
242             command => \@command,
243             );
244 1         116547 $IPC::Cmd::USE_IPC_RUN = $old_use_run;
245              
246 1 50       15 warn "Returned buffer is:\n---\n".join("\n",@$buffer)."\n---" if $self->{debug};
247 1 50       10 warn "Returned error buffer is:\n---\n".join("\n",@$error)."\n---" if $self->{debug};
248              
249 1 50       10 if (not $success) {
250 0         0 croak(
251             "Could not run the specified perl interpreter to determine \@INC. Error code (if any) was: $error_code. STDERR was (if any): ".join('', @$error)
252             );
253             }
254              
255 1         5 my @inc;
256 1         15 my @data = split /\n/, join '', @$buffer;
257 1         6 foreach my $line (@data) {
258 7         21 chomp $line;
259 7 50       20 if ($line eq '%-1;') {
260 0         0 $line = undef;
261             }
262             else {
263 7         16 $line =~ s/%(\d+);/chr($1)/eg;
  0         0  
264             }
265 7         40 push @inc, $line;
266             }
267              
268 1         10 return \@inc;
269             }
270              
271              
272             1;
273             __END__