File Coverage

blib/lib/Devel/CheckApplicationCapabilities.pm
Criterion Covered Total %
statement 184 185 99.4
branch 24 30 80.0
condition 2 3 66.6
subroutine 53 53 100.0
pod 6 6 100.0
total 269 277 97.1


line stmt bran cond sub pod time code
1             package Devel::CheckApplicationCapabilities;
2              
3 5     5   241762 use strict;
  5         15  
  5         200  
4 5     5   30 use Exporter;
  5         9  
  5         303  
5 5     5   27 use Config;
  5         20  
  5         284  
6 5     5   31 use File::Spec;
  5         11  
  5         111  
7 5     5   27 use Cwd;
  5         15  
  5         449  
8              
9 5     5   30 use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS);
  5         11  
  5         7476  
10              
11             $VERSION = '1.1';
12              
13             # localising prevents the warningness leaking out of this module
14             local $^W = 1; # use warnings is a 5.6-ism
15              
16             @ISA = qw(Exporter);
17             @EXPORT_OK = qw(
18             app_is app_isnt
19             die_if_app_is die_if_app_isnt
20             die_unsupported
21             list_app_checks
22             );
23             %EXPORT_TAGS = (
24             all => \@EXPORT_OK,
25             booleans => [qw(app_is app_isnt die_unsupported)],
26             fatal => [qw(die_if_app_is die_if_app_isnt)]
27             );
28              
29             =head1 NAME
30              
31             Devel::CheckApplicationCapabilities - check what an external application
32             is capable of.
33              
34             =head1 DESCRIPTION
35              
36             Devel::CheckApplicationCapabilities provides a nice user-friendly interface
37             to back-end modules for doing things like checking whether tar(1) supports
38             the -z argument and so can be expected to support .tar.gz files.
39              
40             =head1 SYNOPSIS
41              
42             use Devel::CheckApplicationCapabilities qw(app_is);
43             print "Yay, I can gzip!\n"
44             if(app_is('tar' => qw(TarMinusZ)));
45             print "Yay, I can bzip too!\n"
46             if(app_is('tar' => qw(TarMinusJ TarMinusZ)));
47              
48             =head1 FUNCTIONS
49              
50             Devel::CheckApplicationCapabilities implements the following functions, which load subsidiary
51             modules on demand to do the real work. They can be exported
52             by listing their names after C. You can also export
53             groups of functions thus:
54              
55             use Devel::CheckApplicationCapabilities qw(:booleans); # export the boolean functions
56             # and 'die_unsupported'
57            
58             use Devel::CheckApplicationCapabilities qw(:fatal); # export those that die on no match
59              
60             use Devel::CheckApplicationCapabilities qw(:all); # export everything
61              
62             =head2 Boolean functions
63              
64             =head3 app_is
65              
66             Takes an application name and a list of capabilities and returns true
67             if the application has all the capabilities, false otherwise. The
68             application can be
69             specified as a relative path, a full path, or with no path at all in
70             which case C<$ENV{PATH}> will be searched.
71              
72             Each capability corresponds to a
73             Devel::AssertApplicationCapabilities::whatever module.
74              
75             =cut
76              
77             # look in $PATH for $app
78             sub _find_app {
79 33     33   149 my $app = shift;
80 33 100       1278 return $app if(-f $app);
81              
82 6         388 foreach my $path (split(/$Config{path_sep}/, $ENV{PATH})) {
83 36 100       2197 return File::Spec->catfile($path, $app) if(-f File::Spec->catfile($path, $app))
84             }
85 0         0 return $app;
86             }
87              
88             sub app_is {
89 33     33 1 17058 my $app = shift;
90 33         142 $app = _find_app($app);
91 33 50       623 die("Devel::CheckApplicationCapabilities: $app doesn't exist\n")
92             unless(-f $app);
93              
94 33         134 my @targets = @_;
95 33         84 my $rval = 1;
96 33         77 foreach my $target (@targets) {
97 41 50       581 die("Devel::CheckApplicationCapabilities: $target isn't a legal capability name\n")
98             unless($target =~ /^\w+(::\w+)*$/);
99 5     5   3794 eval "use Devel::AssertApplicationCapabilities::$target '$app'";
  4     5   180  
  4     3   45  
  5     3   1167  
  5     1   32  
  5     1   106  
  3     1   1183  
  2     1   10084  
  2     1   54  
  3     1   44  
  3     1   13  
  3     1   76  
  1     1   668  
  1     1   505  
  1     1   17  
  1     1   11  
  1     1   4  
  1     1   23  
  1     1   16  
  1     1   2  
  1     1   22  
  1     1   11  
  1     1   5  
  1     1   16  
  1     1   16  
  1     1   2  
  1     1   22  
  1     1   16  
  1     1   2  
  1         24  
  1         122  
  1         7  
  1         28  
  1         17  
  1         4  
  1         24  
  1         16  
  1         5  
  1         222  
  1         14  
  1         5  
  1         26  
  1         20  
  1         2  
  1         30  
  1         12  
  1         5  
  1         20  
  1         16  
  1         5  
  1         26  
  1         12  
  1         5  
  1         20  
  1         18  
  1         5  
  1         28  
  1         19  
  1         4  
  1         33  
  1         20  
  1         5  
  1         38  
  1         12  
  1         1  
  1         22  
  1         25  
  1         8  
  1         29  
  1         18  
  1         5  
  1         20  
  1         17  
  1         6  
  1         29  
  1         58  
  1         2  
  1         24  
  1         11  
  1         7  
  1         94  
  1         26  
  1         3  
  1         39  
  1         20  
  1         3  
  1         26  
  41         10124  
100 41 100       2338 $rval = 0 if($@);
101             }
102 33         1322 return $rval;
103             }
104              
105             =head3 app_isnt
106              
107             Exactly the same as C, except that it returns true if the
108             app does not have all the capabilities, otherwise it returns false.
109              
110             =cut
111              
112             sub app_isnt {
113 10     10 1 65 my $app = shift;
114 10         43 my @targets = @_;
115 10 100       67 app_is($app, @targets) ? 0 : 1;
116             }
117              
118             =head2 Fatal functions
119              
120             =head3 die_if_app_isnt
121              
122             As C, except that it dies instead of returning false. The die()
123             message matches what the CPAN-testers look for to determine if a module
124             doesn't support a particular platform.
125              
126             =cut
127              
128             sub die_if_app_isnt {
129 2 100   2 1 22 app_is(@_) ? 1 : die_unsupported();
130             }
131              
132             =head3 die_if_app_is
133              
134             As C, except that it dies instead of returning false.
135              
136             =cut
137              
138             sub die_if_app_is {
139 2 100   2 1 27 app_isnt(@_) ? 1 : die_unsupported();
140             }
141              
142             =head2 And some utility functions ...
143              
144             =head3 die_unsupported
145              
146             This function simply dies with the message "OS unsupported", which is what
147             the CPAN testers look for to figure out whether a platform is supported or
148             not. Yes, it says "OS", not "application". Sorry, that's just the way
149             things are.
150              
151             =cut
152              
153 17     17 1 1989 sub die_unsupported { die("OS unsupported\n"); }
154              
155             # takes a subref as its argument. It temporarily closes
156             # STDERR, runs the subref, then restores STDERR.
157             sub _with_STDERR_closed {
158 44 50   44   5325 open(my $REALSTDERR, ">&STDERR") || die("Can't dup STDERR\n");
159 44         365 close(STDERR);
160              
161 44         172 my $rval = shift->();
162              
163 44 50       581238 open(STDERR, '>&', $REALSTDERR) || die("Can't dup saved STDERR\n");
164 44         5797 return $rval;
165             }
166              
167             =head3 list_app_checks
168              
169             When called in list context,
170             return a list of all the capabilities that can be checked, or
171             Devel::AssertApplicationCapabilities::* modules that are available.
172             That includes both those bundled with this module and any third-party
173             add-ons you have installed.
174              
175             In scalar context, returns a hashref keyed by capability with the filename
176             of the most recent version of the supporting module that is available to you.
177              
178             Unfortunately, on some platforms this list may have file case
179             broken. eg, some platforms might return 'gnu' instead of 'GNU'.
180             This is because they have case-insensitive filesystems so things
181             should Just Work anyway.
182              
183             =cut
184              
185             my ($re_Devel, $re_AssertApplicationCapabilities);
186             sub list_app_checks {
187 1     1 1 1238 eval " # only load these if needed
  1     1   9856  
  1     1   15  
  1     1   94  
  1     1   3  
  1     1   17  
  1     1   8  
  1     1   2  
  1     1   9  
  1     1   74  
  1     5   2  
  1         12  
  1         8  
  1         2  
  1         10  
  1         83  
  1         3  
  1         15  
  1         8  
  1         2  
  1         14  
  1         75  
  1         2  
  1         13  
  1         11  
  1         3  
  1         15  
  1         98  
  1         9  
  1         34  
  5         3003996  
188             use File::Find::Rule;
189             use File::Spec;
190             ";
191            
192 5 50       27 die($@) if($@);
193 5 100       18 if (!$re_Devel) {
194 1 50       132 my $case_flag = File::Spec->case_tolerant ? '(?i)' : '';
195 1         17 $re_Devel = qr/$case_flag ^Devel$/x;
196 1         16 $re_AssertApplicationCapabilities = qr/$case_flag ^AssertApplicationCapabilities$/x;
197             }
198              
199             # sort by mtime, so oldest last
200 109         5619 my @modules = sort {
201 46         8425 (stat($a->{file}))[9] <=> (stat($b->{file}))[9]
202             } map {
203 51         1239 my (undef, $dir_part, $file_part) = File::Spec->splitpath($_);
204 46         183 $file_part =~ s/\.pm$//;
205 46         235 my (@dirs) = grep {+length} File::Spec->splitdir($dir_part);
  355         601  
206 46         142 foreach my $i (reverse 1..$#dirs) {
207 51 100 66     543 next unless $dirs[$i] =~ $re_AssertApplicationCapabilities
208             && $dirs[$i - 1] =~ $re_Devel;
209 46         103 splice @dirs, 0, $i + 1;
210 46         114 last;
211             }
212             {
213 46         346 module => join('::', @dirs, $file_part),
214             file => File::Spec->canonpath($_)
215             }
216             } File::Find::Rule->file()->not(File::Find::Rule->name('_*'))->name('*.pm')->in(
217 51         1984 grep { -d }
218 5         158 map { File::Spec->catdir($_, qw(Devel AssertApplicationCapabilities)) }
219             @INC
220             );
221              
222 46         180 my %modules = map {
223 5         81 $_->{module} => $_->{file}
224             } @modules;
225              
226 5 100       24 if(wantarray()) {
227 3         50 return sort keys %modules;
228             } else {
229 2         28 return \%modules;
230             }
231             }
232              
233             =head1 CAPABILITIES SUPPORTED
234              
235             To see the list of capabilities for which information is available, run this:
236              
237             perl -MDevel::CheckApplicationCapabilities=:all -le 'print join(", ", list_app_checks())'
238              
239             Note that capitalisation is important. These are the names of the
240             underlying Devel::AssertApplicationCapabilities::* modules
241             which do the actual platform detection, so they have to
242             be 'legal' filenames and module names, which unfortunately precludes
243             funny characters, so we check for 'tar -z' with 'TarMinusZ'.
244             Sorry.
245              
246             If you want to add your own OSes or families, see L
247             and please feel free to upload the results to the CPAN.
248              
249             =head1 BUGS and FEEDBACK
250              
251             I welcome feedback about my code, including constructive criticism.
252             Bug reports should be made using L or by email.
253              
254             If you are feeling particularly generous you can encourage me in my
255             open source endeavours by buying me something from my wishlist:
256             L
257              
258             =head1 SEE ALSO
259              
260             L
261              
262             L
263              
264             L
265              
266             =head1 AUTHOR
267              
268             David Cantrell EFE
269              
270             =head1 SOURCE CODE REPOSITORY
271              
272             L
273              
274             =head1 COPYRIGHT and LICENCE
275              
276             Copyright 2010 David Cantrell
277              
278             This software is free-as-in-speech software, and may be used, distributed, and modified under the terms of either the GNU General Public Licence version 2 or the Artistic Licence. It's up to you which one you use. The full text of the licences can be found in the files GPL2.txt and ARTISTIC.txt, respectively.
279              
280             =head1 TWEED
281              
282             I recommend buying splendiferous cloth from , especially from their "lumatwill" range.
283              
284             =head1 CONSPIRACY
285              
286             This module is also free-as-in-mason software.
287              
288             =cut
289              
290             1;