File Coverage

blib/lib/Devel/CheckOS.pm
Criterion Covered Total %
statement 255 321 79.4
branch 22 24 91.6
condition 6 11 54.5
subroutine 107 107 100.0
pod 8 8 100.0
total 398 471 84.5


line stmt bran cond sub pod time code
1             package Devel::CheckOS;
2              
3 65     65   1996778 use strict;
  36         584  
  36         1310  
4 44     44   7667 use warnings;
  34         121  
  34         1815  
5              
6 44     44   8334 use Exporter;
  31         67  
  31         1726  
7             # if we're loading this from Makefile.PL, FFR might not yet be installed
8 40     40   21566 eval 'use File::Find::Rule';
  31         280694  
  31         405  
9 43     43   7676 use File::Spec;
  30         85  
  30         1124  
10              
11 44     44   7725 use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS %OS_ALIASES);
  31         75  
  31         22965  
12              
13             our $VERSION = '2.04';
14              
15             @ISA = qw(Exporter);
16             @EXPORT_OK = qw(
17             os_is os_isnt die_if_os_is die_if_os_isnt die_unsupported
18             list_platforms list_family_members register_alias
19             );
20             %EXPORT_TAGS = (
21             all => \@EXPORT_OK,
22             booleans => [qw(os_is os_isnt die_unsupported)],
23             fatal => [qw(die_if_os_is die_if_os_isnt)]
24             );
25              
26             # get a list of the .pm files under a list of dirs, or the empty list
27             # in taint mode
28             sub _find_pm_files_in_dirs {
29 1051     1051   16886 my @files;
30 1043         2200 eval { @files = File::Find::Rule->file()->name('*.pm')->in(@_) };
  1043         47772  
31 1050         19763089 return @files;
32             }
33              
34             if(exists($INC{'File/Find/Rule.pm'})) {
35             foreach my $alias_module (
36             _find_pm_files_in_dirs(
37             grep { -d }
38             map { File::Spec->catdir($_, qw(Devel AssertOS Alias)) }
39             @INC
40             )
41             ) {
42             my(undef, undef, $file_part) = File::Spec->splitpath($alias_module);
43             $file_part =~ s/\.pm$//;
44 38     38   20982 eval "use Devel::AssertOS::Alias::$file_part";
  29     38   99  
  29     29   614  
  38         4612  
  31         86  
  31         428  
  29         5640  
  21         45  
  21         228  
45             warn("Bad alias module 'Devel::AssertOS::Alias::$file_part' ignored\n") if($@);
46             }
47             }
48              
49             =head1 NAME
50              
51             Devel::CheckOS - check what OS we're running on
52              
53             =head1 DESCRIPTION
54              
55             A learned sage once wrote on IRC:
56              
57             $^O is stupid and ugly, it wears its pants as a hat
58              
59             Devel::CheckOS provides a more friendly interface to $^O, and also lets
60             you check for various OS "families" such as "Unix", which includes things
61             like Linux, Solaris, AIX etc.
62              
63             It spares perl the embarrassment of wearing its pants on its head by
64             covering them with a splendid Fedora.
65              
66             =head1 SYNOPSIS
67              
68             use Devel::CheckOS qw(os_is);
69             print "Hey, I know this, it's a Unix system\n" if(os_is('Unix'));
70              
71             print "You've got Linux 2.6\n" if(os_is('Linux::v2_6'));
72              
73             =head1 USING IT IN Makefile.PL or Build.PL
74              
75             If you want to use this from Makefile.PL or Build.PL, do
76             not simply copy the module into your distribution as this may cause
77             problems when PAUSE and search.cpan.org index the distro. Instead, use
78             the use-devel-assertos script.
79              
80             =head1 FUNCTIONS
81              
82             Devel::CheckOS implements the following functions, which load subsidiary
83             OS-specific modules on demand to do the real work. They can all be exported
84             by listing their names after C. You can also export
85             groups of functions thus:
86              
87             use Devel::CheckOS qw(:booleans); # export the boolean functions
88             # and 'die_unsupported'
89            
90             use Devel::CheckOS qw(:fatal); # export those that die on no match
91              
92             use Devel::CheckOS qw(:all); # export everything exportable
93              
94             =head2 Boolean functions
95              
96             =head3 os_is
97              
98             Takes a list of OS names. If the current platform matches any of them,
99             it returns true, otherwise it returns false. The names can be a mixture
100             of OSes and OS families, eg ...
101              
102             os_is(qw(Unix VMS)); # Unix is a family, VMS is an OS
103              
104             Matching is case-insensitive provided that Taint-mode is not enabled, so the
105             above could also be written:
106              
107             os_is(qw(unix vms));
108              
109             =cut
110              
111             sub os_is {
112 648     653 1 1573285 my @targets = @_;
113 648         1524 my $rval = 0;
114              
115 653         6167 TARGET: foreach my $target (@targets) {
116             # resolve aliases
117 1004         4024 ALIAS: foreach my $alias (keys %OS_ALIASES) {
118 1004 100       8845 if($target =~ /^$alias$/i) {
119 11         4059 $target = $OS_ALIASES{$alias};
120 4         37 last ALIAS;
121             }
122             }
123              
124             # resolve case-insensitive names (no-op in taint-mode as list_platforms
125             # won't work)
126 1006         3211 my @available_platforms = list_platforms();
127 1013         7916 CANDIDATE: foreach my $candidate (@available_platforms) {
128 35279 100       301048 if($target =~ /^\Q$candidate\E$/i) {
129 1005         2675 $target = $candidate;
130 1012         7024 last CANDIDATE;
131             }
132             }
133              
134 1006 100       8521 die("Devel::CheckOS: $target isn't a legal OS name\n")
135             unless($target =~ /^\w+(::\w+)*$/);
136              
137 1005         2515 $@ = undef;
138 1012 100       21041 if(! "Devel::AssertOS::$target"->can('os_is')) {
139 35     35   20060 eval "use Devel::AssertOS::$target";
  17     13   1997  
  17     13   497  
  271     12   32379  
  6     12   2567  
  6     12   842  
  4     12   80  
  6     11   110  
  8     9   1204  
  6     9   193  
  5     4   1188  
  6     4   405  
  4     4   53  
  5     4   102  
  7     4   539  
  5     4   116  
  5     4   1076  
  4     4   417  
  2     4   4  
  5     2   85  
  7     2   536  
  5     2   116  
  4     2   598  
  4     2   663  
  2     2   4  
  2     2   122  
  4     2   1230  
  3     2   8  
  3     2   101  
  2     2   47  
  0     2   0  
  0         0  
  2         12  
  2         5  
  2         69  
  2         1053  
  0         0  
  0         0  
  2         14  
  2         4  
  2         67  
  2         956  
  0         0  
  0         0  
  2         21  
  2         5  
  2         115  
  2         442  
  0         0  
  0         0  
  2         15  
  2         5  
  2         79  
  2         486  
  0         0  
  0         0  
  2         15  
  2         6  
  2         77  
  2         1361  
  0         0  
  0         0  
  2         29  
  2         6  
  2         115  
  2         749  
  0         0  
  0         0  
  2         20  
  2         4  
  2         125  
  2         670  
  0         0  
  0         0  
  2         16  
  2         5  
  2         77  
  2         677  
  0         0  
  0         0  
  2         15  
  2         6  
  2         75  
  2         742  
  0         0  
  0         0  
  2         15  
  2         14  
  2         78  
  2         646  
  1         3  
  1         17  
  2         17  
  2         5  
140             }
141 1005 100       6756 if(!$@) {
142 41     41   6805 no strict 'refs';
  29         57  
  29         24082  
143 777 100       6062 $rval = 1 if(&{"Devel::AssertOS::${target}::os_is"}());
  770         5172  
144             }
145             }
146 646         15704 return $rval;
147             }
148              
149             =head3 os_isnt
150              
151             If the current platform matches (case-insensitively) any of the parameters it
152             returns false, otherwise it returns true.
153              
154             =cut
155              
156             sub os_isnt {
157 64     63 1 19341 my @targets = @_;
158 56         131 my $rval = 1;
159 56         209 foreach my $target (@targets) {
160 85 100       4812 $rval = 0 if(os_is($target));
161             }
162 57         1945 return $rval;
163             }
164              
165             =head2 Fatal functions
166              
167             =head3 die_if_os_isnt
168              
169             As C, except that it dies instead of returning false. The die()
170             message matches what the CPAN-testers look for to determine if a module
171             doesn't support a particular platform.
172              
173             =cut
174              
175             sub die_if_os_isnt {
176 11 100   18 1 238476 os_is(@_) ? 1 : die_unsupported();
177             }
178              
179             =head3 die_if_os_is
180              
181             As C, except that it dies instead of returning false.
182              
183             =cut
184              
185             sub die_if_os_is {
186 19 100   19 1 6858 os_isnt(@_) ? 1 : die_unsupported();
187             }
188              
189             =head2 And some utility functions ...
190              
191             =head3 die_unsupported
192              
193             This function simply dies with the message "OS unsupported", which is what
194             the CPAN testers look for to figure out whether a platform is supported or
195             not.
196              
197             =cut
198              
199 322     330 1 12464 sub die_unsupported { die("OS unsupported\n"); }
200              
201             =head3 list_platforms
202              
203             Return a list of all the platforms for which the corresponding
204             Devel::AssertOS::* module is available. This includes both OSes and OS
205             families, and both those bundled with this module and any third-party
206             add-ons you have installed.
207              
208             Unfortunately, on some platforms this list may have platform names'
209             case broken, eg you might see 'freebsd' instead of 'FreeBSD'.
210             This is because they have case-insensitive filesystems so things
211             should Just Work anyway.
212              
213             This function does not work in taint-mode.
214              
215             =cut
216              
217             my $case_flag = File::Spec->case_tolerant ? '(?i)' : '';
218             my $re_Devel = qr/$case_flag ^Devel$/x;
219             my $re_AssertOS = qr/$case_flag ^AssertOS$/x;
220             my $re_Alias = qr/$case_flag ^Alias\b/x;
221              
222             sub list_platforms {
223 1014     1022 1 1119235 my @modules = sort keys %{ {map { $_ => 1 } grep {
  301715         667086  
224 304555         719113 $_ !~ $re_Alias
225             } map {
226 304562         2013089 my (undef, $dir_part, $file_part) = File::Spec->splitpath($_);
227 304554         870483 $file_part =~ s/\.pm$//;
228 304554         1177604 my (@dirs) = grep {+length} File::Spec->splitdir($dir_part);
  3187350         4809160  
229 304556         806069 foreach my $i (reverse 1..$#dirs) {
230             next unless(
231 449732 100 66     2539943 $dirs[$i] =~ $re_AssertOS &&
232             $dirs[$i - 1] =~ $re_Devel
233             );;
234 304562         669581 splice @dirs, 0, $i + 1;
235 304555         446945 last;
236             }
237 304555         838941 join('::', @dirs, $file_part);
238             } _find_pm_files_in_dirs(
239 8083         110721 grep { -d }
240 1022         7740 map { File::Spec->catdir($_, qw(Devel AssertOS)) }
  8077         46903  
241             @INC
242             )}};
243              
244 1016         85783 return @modules;
245             }
246              
247             =head3 list_family_members
248              
249             Takes the name of an OS 'family' and returns a list of all its members.
250              
251             If called on something that isn't a family, you get an empty list.
252              
253             =cut
254              
255             sub list_family_members {
256 124   100 124 1 10314289 my $family = shift() ||
257             die(__PACKAGE__."::list_family_members needs a parameter\n");
258              
259             # this will die if it's the wrong OS, but the module is loaded ...
260 118     2   8852 eval qq{use Devel::AssertOS::$family};
  2     2   80  
  2     2   726  
  0     2   0  
  2     2   89  
  2     2   648  
  0     2   0  
  2     2   68  
  2     2   581  
  0     1   0  
  2     1   61  
  2     1   417  
  0     1   0  
  2     1   62  
  1     1   486  
  0     1   0  
  1     1   34  
  1     1   418  
  0     1   0  
  1     1   32  
  1     1   408  
  0     1   0  
  1     1   33  
  1     1   458  
  0     1   0  
  1     1   50  
  1     1   712  
  0     1   0  
  1     1   55  
  1         765  
  0         0  
  1         52  
  1         20  
  0         0  
  1         30  
  1         677  
  0         0  
  1         32  
  1         554  
  0         0  
  1         47  
  1         666  
  0         0  
  1         33  
  1         539  
  0         0  
  1         33  
  1         527  
  0         0  
  1         53  
  1         524  
  0         0  
  1         33  
  1         523  
  0         0  
  1         33  
  1         616  
  0         0  
  1         34  
  1         562  
  0         0  
  1         33  
  1         39  
  0         0  
  1         42  
  1         47  
  0         0  
  1         36  
  1         20  
  0         0  
  1         29  
  1         607  
  1         4  
261             # ... so we can now query it
262 118     2   15702 return eval qq{
  0     2   0  
  2     2   18  
  2     2   5  
  0     2   0  
  2     2   12  
  2     2   5  
  0     2   0  
  2     2   11  
  2     1   5  
  0     1   0  
  2     1   11  
  2     1   5  
  0     1   0  
  1     1   6  
  1     1   1  
  0     1   0  
  1     1   6  
  1     1   2  
  0     1   0  
  1     1   6  
  1     1   1  
  0     1   0  
  1     1   12  
  1     1   3  
  0     1   0  
  1     1   12  
  1     1   2  
  0         0  
  1         10  
  1         3  
  0         0  
  1         6  
  1         2  
  0         0  
  1         6  
  1         2  
  0         0  
  1         11  
  1         2  
  0         0  
  1         7  
  1         3  
  0         0  
  1         7  
  1         2  
  0         0  
  1         7  
  1         4  
  0         0  
  1         6  
  1         3  
  0         0  
  1         6  
  1         2  
  0         0  
  1         7  
  1         3  
  0         0  
  1         6  
  1         2  
  0         0  
  1         5  
  1         2  
  0         0  
  1         7  
  1         2  
  0         0  
  1         6  
  1         2  
  1         76  
263             no strict 'refs';
264             &{"Devel::AssertOS::${family}::matches"}()
265             };
266             }
267              
268             =head3 register_alias
269              
270             It takes two arguments, the first being an alias name, the second being the
271             name of an OS. After the alias has been registered, any queries about the
272             alias will return the appropriate result for the named OS.
273              
274             It returns true unless you invoke it incorrectly or you attempt to change
275             an existing alias.
276              
277             Aliases don't work under taint-mode.
278              
279             See L.
280              
281             =cut
282              
283             sub register_alias {
284 38     38 1 4355 my($alias, $os) = @_;
285 31 50 33     259 ($alias && $os) || return 0;
286 31 50 33     305 if(!exists($OS_ALIASES{$alias}) || $OS_ALIASES{$alias} eq $os) {
287 33         1356 return $OS_ALIASES{$alias} = $os;
288             } else {
289 2         10 return 0
290             }
291             }
292              
293             =head1 PLATFORMS SUPPORTED
294              
295             To see the list of platforms for which information is available, run this:
296              
297             perl -MDevel::CheckOS -e 'print join(", ", Devel::CheckOS::list_platforms())'
298              
299             These are the names of the underlying Devel::AssertOS::* modules
300             which do the actual platform detection, so they have to
301             be 'legal' filenames and module names, which unfortunately precludes
302             funny characters, so platforms like OS/2 are mis-spelt deliberately.
303             Sorry.
304              
305             Also be aware that not all of them have been properly tested. I don't
306             have access to most of them and have had to work from information
307             gleaned from L and a few other places. For a complete list of
308             OS families, see L.
309              
310             If you want to add your own OSes or families, see L
311             and please feel free to upload the results to the CPAN.
312              
313             =head1 BUGS and FEEDBACK
314              
315             I welcome feedback about my code, including constructive criticism.
316             Bug reports should be made using L.
317              
318             You will need to include in your bug report the exact value of $^O, what
319             the OS is called (eg Windows Vista 64 bit Ultimate Home Edition), and,
320             if relevant, what "OS family" it should be in and who wrote it.
321              
322             If you are feeling particularly generous you can encourage me in my
323             open source endeavours by buying me something from my wishlist:
324             L
325              
326             =head1 COMPATIBILITY
327              
328             Version 1.90 made all matches case-insensitive. This is a change in behaviour, but
329             if it breaks your code then your code was already broken, you just didn't know it.
330              
331             As of version 2.00 the list_* functions always return plain old lists. Calling them
332             in scalar context was deprecated and has emitted warnings for over 2 years, since
333             version 1.90.
334              
335             =head1 SEE ALSO
336              
337             $^O in L
338              
339             L
340              
341             L
342              
343             L
344              
345             L
346              
347             The use-devel-assertos script
348              
349             L
350              
351             =head1 AUTHOR
352              
353             David Cantrell EFE
354              
355             Thanks to David Golden for the name and ideas about the interface, and
356             to the cpan-testers-discuss mailing list for prompting me to write it
357             in the first place.
358              
359             Thanks to Ken Williams, from whose L I lifted some of the
360             information about what should be in the Unix family.
361              
362             Thanks to Billy Abbott for finding some bugs for me on VMS.
363              
364             Thanks to Matt Kraai for information about QNX.
365              
366             Thanks to Kenichi Ishigaki and Gabor Szabo for reporting a bug on Windows,
367             and to the former for providing a patch.
368              
369             Thanks to Paul Green for some information about VOS.
370              
371             Thanks to Yanick Champoux for a patch to let Devel::AssertOS support
372             negative assertions.
373              
374             Thanks to Brian Fraser for adding Android support.
375              
376             Thanks to Dale Evans for Debian detection, a bunch of Mac OS X specific version
377             detection modules, and perl 5.6 support.
378              
379             Thanks to Graham Knop for fixing a build bug on perl 5.8.
380              
381             Thanks to Alceu Rodrigues de Freitas Junior for improving Ubuntu detection
382             and providing a way to detect a lot more Linux variants.
383              
384             Thanks to Leos Stejskal for https://github.com/stejskalleos/os_release from
385             which I got many sample /etc/os-release files.
386              
387             =head1 SOURCE CODE REPOSITORY
388              
389             L
390              
391             =head1 COPYRIGHT and LICENCE
392              
393             Copyright 2024 David Cantrell
394              
395             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.
396              
397             =head1 HATS
398              
399             I recommend buying a Fedora from L.
400              
401             =head1 CONSPIRACY
402              
403             This module is also free-as-in-mason software.
404              
405             =cut
406              
407             1;