File Coverage

blib/lib/File/ConfigDir.pm
Criterion Covered Total %
statement 98 103 95.1
branch 24 42 57.1
condition 3 3 100.0
subroutine 27 28 96.4
pod 13 13 100.0
total 165 189 87.3


line stmt bran cond sub pod time code
1             package File::ConfigDir;
2              
3 3     3   39734 use warnings;
  3         7  
  3         84  
4 3     3   14 use strict;
  3         5  
  3         68  
5 3     3   13 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  3         9  
  3         209  
6              
7 3     3   17 use Carp qw(croak);
  3         6  
  3         127  
8 3     3   17 use Config;
  3         7  
  3         129  
9 3     3   17 use Cwd ();
  3         7  
  3         32  
10 3     3   9 use Exporter ();
  3         7  
  3         39  
11 3     3   1059 use FindBin ();
  3         2267  
  3         54  
12 3     3   16 use File::Basename ();
  3         6  
  3         30  
13 3     3   23 use File::Spec ();
  3         5  
  3         1386  
14              
15             =head1 NAME
16              
17             File::ConfigDir - Get directories of configuration files
18              
19             =cut
20              
21             $VERSION = '0.018';
22             @ISA = qw(Exporter);
23             @EXPORT = ();
24             @EXPORT_OK = (
25             qw(config_dirs system_cfg_dir desktop_cfg_dir),
26             qw(xdg_config_dirs machine_cfg_dir),
27             qw(core_cfg_dir site_cfg_dir vendor_cfg_dir),
28             qw(locallib_cfg_dir local_cfg_dir),
29             qw(here_cfg_dir singleapp_cfg_dir vendorapp_cfg_dir),
30             qw(xdg_config_home user_cfg_dir)
31             );
32             %EXPORT_TAGS = (
33             ALL => [@EXPORT_OK],
34             );
35              
36             my $haveFileHomeDir = 0;
37             eval {
38             require File::HomeDir;
39             $haveFileHomeDir = 1;
40             };
41              
42 3     3   1365 eval "use List::MoreUtils qw/uniq/;";
  3         26263  
  3         22  
43             __PACKAGE__->can("uniq") or eval <<'EOP';
44             # from PP part of List::MoreUtils
45             sub uniq(&@) {
46             my %h;
47             map { $h{$_}++ == 0 ? $_ : () } @_;
48             }
49             EOP
50              
51             =head1 SYNOPSIS
52              
53             use File::ConfigDir ':ALL';
54              
55             my @cfgdirs = config_dirs();
56             my @appcfgdirs = config_dirs('app');
57              
58             # install support
59             my $site_cfg_dir = (site_cfg_dir())[0];
60             my $vendor_cfg_dir = (site_cfg_dir()))[0];
61              
62             =head1 DESCRIPTION
63              
64             This module is a helper for installing, reading and finding configuration
65             file locations. It's intended to work in every supported Perl5 environment
66             and will always try to Do The Right Thing(tm).
67              
68             C is a module to help out when perl modules (especially
69             applications) need to read and store configuration files from more than
70             one location. Writing user configuration is easy thanks to
71             L, but what when the system administrator needs to place
72             some global configuration or there will be system related configuration
73             (in C on UNIX(tm) or C<$ENV{windir}> on Windows(tm)) and some
74             network configuration in nfs mapped C or
75             C<$ENV{ALLUSERSPROFILE} . "\\Application Data\\p5-app">, respectively.
76              
77             C has no "do what I mean" mode - it's entirely up to the
78             user to pick the right directory for each particular application.
79              
80             =head1 EXPORT
81              
82             Every function listed below can be exported, either by name or using the
83             tag C<:ALL>.
84              
85             =head1 SUBROUTINES/METHODS
86              
87             All functions can take one optional argument as application specific
88             configuration directory. If given, it will be embedded at the right (tm)
89             place of the resulting path.
90              
91             =cut
92              
93             sub _find_common_base_dir
94             {
95 4     4   157 my ($dira, $dirb) = @_;
96 4         55 my ($va, $da, undef) = File::Spec->splitpath($dira);
97 4         31 my ($vb, $db, undef) = File::Spec->splitpath($dirb);
98 4         31 my @dirsa = File::Spec->splitdir($da);
99 4         17 my @dirsb = File::Spec->splitdir($db);
100 4         7 my @commondir;
101 4 50       17 my $max = $#dirsa < $#dirsb ? $#dirsa : $#dirsb;
102 4         16 for my $i (0 .. $max)
103             {
104 0 0       0 $dirsa[$i] eq $dirsb[$i] or last;
105 0         0 push(@commondir, $dirsa[$i]);
106             }
107              
108 4         27 File::Spec->catdir($va, @commondir);
109             }
110              
111             =head2 system_cfg_dir
112              
113             Returns the configuration directory where configuration files of the
114             operating system resides. For Unices this is C, for MSWin32 it's
115             the value of the environment variable C<%windir%>.
116              
117             =cut
118              
119             my $system_cfg_dir = sub {
120             my @cfg_base = @_;
121             my @dirs = File::Spec->catdir($^O eq "MSWin32" ? $ENV{windir} : "/etc", @cfg_base);
122             @dirs;
123             };
124              
125             sub system_cfg_dir
126             {
127 1     1 1 1082 my @cfg_base = @_;
128 1 50       5 1 < scalar(@cfg_base)
129             and croak "system_cfg_dir(;\$), not system_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
130 1         8 $system_cfg_dir->(@cfg_base);
131             }
132              
133             =head2 machine_cfg_dir
134              
135             Alias for desktop_cfg_dir - deprecated.
136              
137             =head2 xdg_config_dirs
138              
139             Alias for desktop_cfg_dir
140              
141             =head2 desktop_cfg_dir
142              
143             Returns the configuration directory where configuration files of the
144             desktop applications resides. For Unices this is C, for MSWin32
145             it's the value of the environment variable C<%ALLUSERSPROFILE%>
146             concatenated with the basename of the environment variable C<%APPDATA%>.
147              
148             =cut
149              
150             my $desktop_cfg_dir = sub {
151             my @cfg_base = @_;
152             my @dirs;
153             if ($^O eq "MSWin32")
154             {
155             my $alluserprof = $ENV{ALLUSERSPROFILE};
156             my $appdatabase = File::Basename::basename($ENV{APPDATA});
157             @dirs = (File::Spec->catdir($alluserprof, $appdatabase, @cfg_base));
158             }
159             else
160             {
161             if ($ENV{XDG_CONFIG_DIRS})
162             {
163             @dirs = split(":", $ENV{XDG_CONFIG_DIRS});
164             @dirs = map { File::Spec->catdir($_, @cfg_base) } @dirs;
165             }
166             else
167             {
168             @dirs = (File::Spec->catdir("/etc", "xdg", @cfg_base));
169             }
170             }
171             @dirs;
172             };
173              
174             sub desktop_cfg_dir
175             {
176 2     2 1 1928 my @cfg_base = @_;
177 2 50       9 1 < scalar(@cfg_base)
178             and croak "desktop_cfg_dir(;\$), not desktop_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
179 2         5 $desktop_cfg_dir->(@cfg_base);
180             }
181              
182 3     3   19 no warnings 'once';
  3         8  
  3         133  
183             *machine_cfg_dir = \&desktop_cfg_dir;
184             *xdg_config_dirs = \&desktop_cfg_dir;
185 3     3   15 use warnings;
  3         5  
  3         5116  
186              
187             =head2 core_cfg_dir
188              
189             Returns the C directory below C<$Config{prefix}>.
190              
191             =cut
192              
193             my $core_cfg_dir = sub {
194             my @cfg_base = @_;
195             my @dirs = (File::Spec->catdir($Config{prefix}, "etc", @cfg_base));
196             @dirs;
197             };
198              
199             sub core_cfg_dir
200             {
201 1     1 1 910 my @cfg_base = @_;
202 1 50       24 1 < scalar(@cfg_base)
203             and croak "core_cfg_dir(;\$), not core_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
204 1         4 $core_cfg_dir->(@cfg_base);
205             }
206              
207             =head2 site_cfg_dir
208              
209             Returns the C directory below C<$Config{sitelib_stem}> or the common
210             base directory of C<$Config{sitelib}> and C<$Config{sitebin}>.
211              
212             =cut
213              
214             my $site_cfg_dir = sub {
215             my @cfg_base = @_;
216             my @dirs;
217              
218             if ($Config{sitelib_stem})
219             {
220             push(@dirs, File::Spec->catdir($Config{sitelib_stem}, "etc", @cfg_base));
221             }
222             else
223             {
224             my $sitelib_stem = _find_common_base_dir($Config{sitelib}, $Config{sitebin});
225             push(@dirs, File::Spec->catdir($sitelib_stem, "etc", @cfg_base));
226             }
227              
228             @dirs;
229             };
230              
231             sub site_cfg_dir
232             {
233 1     1 1 911 my @cfg_base = @_;
234 1 50       4 1 < scalar(@cfg_base)
235             and croak "site_cfg_dir(;\$), not site_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
236 1         4 $site_cfg_dir->(@cfg_base);
237             }
238              
239             =head2 vendor_cfg_dir
240              
241             Returns the C directory below C<$Config{vendorlib_stem}> or the common
242             base directory of C<$Config{vendorlib}> and C<$Config{vendorbin}>.
243              
244             =cut
245              
246             my $vendor_cfg_dir = sub {
247             my @cfg_base = @_;
248             my @dirs;
249              
250             if ($Config{vendorlib_stem})
251             {
252             push(@dirs, File::Spec->catdir($Config{vendorlib_stem}, "etc", @cfg_base));
253             }
254             else
255             {
256             my $vendorlib_stem = _find_common_base_dir($Config{vendorlib}, $Config{vendorbin});
257             push(@dirs, File::Spec->catdir($vendorlib_stem, "etc", @cfg_base));
258             }
259              
260             @dirs;
261             };
262              
263             sub vendor_cfg_dir
264             {
265 1     1 1 912 my @cfg_base = @_;
266 1 50       5 1 < scalar(@cfg_base)
267             and croak "vendor_cfg_dir(;\$), not vendor_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
268 1         4 $vendor_cfg_dir->(@cfg_base);
269             }
270              
271             =head2 singleapp_cfg_dir
272              
273             Returns the configuration file for standalone installed applications. In
274             Unix speak, installing JRE to C<< /usr/local/jre- >> means there is
275             a C<< /usr/local/jre-/bin/java >> and going from it's directory
276             name one above and into C there is the I. For a
277             Perl module it means, we're assuming that C<$FindBin::Bin> is installed as
278             a standalone package somewhere, eg. into C - as recommended for
279             L.
280              
281             =cut
282              
283             my $singleapp_cfg_dir = sub {
284             my @dirs = (
285             map {
286             eval { Cwd::abs_path($_) }
287             or File::Spec->canonpath($_)
288             } File::Spec->catdir($FindBin::RealDir, "..", "etc")
289             );
290             @dirs;
291             };
292              
293             sub singleapp_cfg_dir
294             {
295 1     1 1 924 my @cfg_base = @_;
296 1 50       9 0 == scalar(@cfg_base)
297             or croak "singleapp_cfg_dir(), not singleapp_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
298 1         3 $singleapp_cfg_dir->();
299             }
300              
301             =head2 vendorapp_cfg_dir
302              
303             Returns the configuration file for vendot installed applications. In Unix
304             speak, installing bacula to C<< /opt/${vendor} >> means there is
305             a C<< /opt/${vendor}/bin/bacula >> and going from it's directory
306             name one above and into C there is the I. For a
307             Perl module it means, we're assuming that C<$FindBin::Bin> is installed as
308             a standalone package somewhere, eg. into C - as recommended for
309             L.
310              
311             =cut
312              
313             my $vendorapp_cfg_dir = sub {
314             my @cfg_base = @_;
315             my @dirs = (
316             map {
317             eval { Cwd::abs_path($_) }
318             or File::Spec->canonpath($_)
319             } File::Spec->catdir($FindBin::RealDir, "..", "etc", @cfg_base)
320             );
321             @dirs;
322             };
323              
324             sub vendorapp_cfg_dir
325             {
326 1     1 1 907 my @cfg_base = @_;
327 1 50       7 1 < scalar(@cfg_base)
328             and croak "vendorapp_cfg_dir(;\$), not vendorapp_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
329 1         5 $vendorapp_cfg_dir->(@cfg_base);
330             }
331              
332             =head2 local_cfg_dir
333              
334             Returns the configuration directory for distribution independent, 3rd
335             party applications. While this directory doesn't exists for MSWin32,
336             there will be only the path C for Unices.
337              
338             =cut
339              
340             my $local_cfg_dir = sub {
341             my @cfg_base = @_;
342             my @dirs;
343              
344             unless ($^O eq "MSWin32")
345             {
346             push(@dirs, File::Spec->catdir("/usr", "local", "etc", @cfg_base));
347             }
348              
349             @dirs;
350             };
351              
352             sub local_cfg_dir
353             {
354 1     1 1 941 my @cfg_base = @_;
355 1 50       5 1 < scalar(@cfg_base)
356             and croak "local_cfg_dir(;\$), not local_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
357 1         3 $local_cfg_dir->(@cfg_base);
358             }
359              
360             =head2 locallib_cfg_dir
361              
362             Extracts the C from C<$ENV{PERL_MM_OPT}> and returns the
363             C directory below it.
364              
365             =cut
366              
367             my $locallib_cfg_dir = sub {
368             my @cfg_base = @_;
369             my @dirs;
370              
371             if ( $INC{'local/lib.pm'}
372             && $ENV{PERL_MM_OPT}
373             && $ENV{PERL_MM_OPT} =~ m/.*INSTALL_BASE=([^"']*)['"]?$/)
374             {
375             (my $cfgdir = $ENV{PERL_MM_OPT}) =~ s/.*INSTALL_BASE=([^"']*)['"]?$/$1/;
376             push(@dirs, File::Spec->catdir($cfgdir, "etc", @cfg_base));
377             }
378              
379             @dirs;
380             };
381              
382             sub locallib_cfg_dir
383             {
384 0     0 1 0 my @cfg_base = @_;
385 0 0       0 1 < scalar(@cfg_base)
386             and croak "locallib_cfg_dir(;\$), not locallib_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
387 0         0 $locallib_cfg_dir->(@cfg_base);
388             }
389              
390             =head2 here_cfg_dir
391              
392             Returns the path for the C directory below the current working directory.
393              
394             =cut
395              
396             my $here_cfg_dir = sub {
397             my @cfg_base = @_;
398             my @dirs = (File::Spec->catdir(File::Spec->rel2abs(File::Spec->curdir()), @cfg_base, "etc"));
399             @dirs;
400             };
401              
402             sub here_cfg_dir
403             {
404 1     1 1 899 my @cfg_base = @_;
405 1 50       5 1 < scalar(@cfg_base)
406             and croak "here_cfg_dir(;\$), not here_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
407 1         4 $here_cfg_dir->(@cfg_base);
408             }
409              
410             =head2 user_cfg_dir
411              
412             Returns the users home folder using L. Without
413             File::HomeDir, nothing is returned.
414              
415             =cut
416              
417             my $user_cfg_dir = sub {
418             my @cfg_base = @_;
419             my @dirs;
420              
421             $haveFileHomeDir and @dirs = (File::Spec->catdir(File::HomeDir->my_home(), map { "." . $_ } @cfg_base));
422              
423             @dirs;
424             };
425              
426             sub user_cfg_dir
427             {
428 1     1 1 941 my @cfg_base = @_;
429 1 50       5 1 < scalar(@cfg_base)
430             and croak "user_cfg_dir(;\$), not user_cfg_dir(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
431 1         3 $user_cfg_dir->(@cfg_base);
432             }
433              
434             =head2 xdg_config_home
435              
436             Returns the user configuration directory for desktop applications.
437             If C<< $ENV{XDG_CONFIG_HOME} >> is not set, for MSWin32 the value
438             of C<< $ENV{APPDATA} >> is return and on Unices the C<.config> directory
439             in the users home folder. Without L, on Unices the returned
440             list might be empty.
441              
442             =cut
443              
444             my $xdg_config_home = sub {
445             my @cfg_base = @_;
446             my @dirs;
447              
448             if ($ENV{XDG_CONFIG_HOME})
449             {
450             @dirs = split(":", $ENV{XDG_CONFIG_HOME});
451             @dirs = map { File::Spec->catdir($_, @cfg_base) } @dirs;
452             }
453             elsif ($^O eq "MSWin32")
454             {
455             @dirs = (File::Spec->catdir($ENV{APPDATA}, @cfg_base));
456             }
457             else
458             {
459             $haveFileHomeDir and @dirs = (File::Spec->catdir(File::HomeDir->my_home(), ".config", @cfg_base));
460             }
461              
462             @dirs;
463             };
464              
465             sub xdg_config_home
466             {
467 1     1 1 910 my @cfg_base = @_;
468 1 50       5 1 < scalar(@cfg_base)
469             and croak "xdg_config_home(;\$), not xdg_config_home(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
470 1         4 $xdg_config_home->(@cfg_base);
471             }
472              
473             my (@extensible_bases, @pure_bases);
474             push(@extensible_bases,
475             $system_cfg_dir, $desktop_cfg_dir, $local_cfg_dir, $singleapp_cfg_dir, $vendorapp_cfg_dir, $core_cfg_dir,
476             $site_cfg_dir, $vendor_cfg_dir, $here_cfg_dir, $user_cfg_dir, $xdg_config_home);
477             push(@pure_bases, 3);
478              
479             =head2 config_dirs
480              
481             @cfgdirs = config_dirs();
482             @cfgdirs = config_dirs( 'appname' );
483              
484             Tries to get all available configuration directories as described above.
485             Returns those who exists and are readable.
486              
487             =cut
488              
489             sub config_dirs
490             {
491 3     3 1 2648 my @cfg_base = @_;
492 3 50       11 1 < scalar(@cfg_base)
493             and croak "config_dirs(;\$), not config_dirs(" . join(",", ("\$") x scalar(@cfg_base)) . ")";
494 3         8 my @dirs = ();
495              
496 3         7 my $pure_idx = 0;
497 3         11 foreach my $idx (0 .. $#extensible_bases)
498             {
499 37         68 my $pure;
500 37 100 100     146 $pure_idx <= $#pure_bases and $idx == $pure_bases[$pure_idx] and $pure = ++$pure_idx;
501 37 100       125 push(@dirs, $extensible_bases[$idx]->(($pure ? () : @cfg_base)));
502             }
503              
504 3 100       74 @dirs = grep { -d $_ && -r $_ } uniq(@dirs);
  27         409  
505              
506 3         19 @dirs;
507             }
508              
509             =head2 _plug_dir_source
510              
511             my $dir_src = sub { return _better_config_dir(@_); }
512             File::ConfigDir::_plug_dir_source($dir_src);
513              
514             my $pure_src = sub { return _better_config_plain_dir(@_); }
515             File::ConfigDir::_plug_dir_source($pure_src, 1); # see 2nd arg is true
516              
517             Registers more sources to ask for suitable directories to check or search
518             for config files. Each L will traverse them in subsequent
519             invocations, too.
520              
521             Returns the number of directory sources in case of succes. Returns nothing
522             when C<$dir_src> is not a code ref.
523              
524             =cut
525              
526             sub _plug_dir_source
527             {
528 4     4   639 my ($dir_source, $pure) = @_;
529              
530 4 100       16 $dir_source or return;
531 2 50       9 "CODE" eq ref $dir_source or return;
532              
533 2         6 push(@extensible_bases, $dir_source);
534 2 100       6 $pure and push(@pure_bases, $#extensible_bases);
535 2         10 1;
536             }
537              
538             =head1 AUTHOR
539              
540             Jens Rehsack, C<< >>
541              
542             =head1 BUGS
543              
544             Please report any bugs or feature requests to
545             C, or through the web interface at
546             L.
547             I will be notified, and then you'll automatically be notified of progress
548             on your bug as I make changes.
549              
550             =head1 SUPPORT
551              
552             You can find documentation for this module with the perldoc command.
553              
554             perldoc File::ConfigDir
555              
556             You can also look for information at:
557              
558             =over 4
559              
560             =item * RT: CPAN's request tracker
561              
562             L
563              
564             =item * AnnoCPAN: Annotated CPAN documentation
565              
566             L
567              
568             =item * CPAN Ratings
569              
570             L
571              
572             =item * Search CPAN
573              
574             L
575              
576             =back
577              
578             =head1 ACKNOWLEDGEMENTS
579              
580             Thanks are sent out to Lars Dieckow (daxim) for his suggestion to add
581             support for the Base Directory Specification of the Free Desktop Group.
582             Matthew S. Trout (mst) earns the credit to suggest C
583             and remind about C.
584              
585             =head1 LICENSE AND COPYRIGHT
586              
587             Copyright 2010-2017 Jens Rehsack.
588              
589             This program is free software; you can redistribute it and/or modify it
590             under the terms of either: the GNU General Public License as published
591             by the Free Software Foundation; or the Artistic License.
592              
593             See http://dev.perl.org/licenses/ for more information.
594              
595             =head1 SEE ALSO
596              
597             L, L, L (Unices only)
598              
599             =cut
600              
601             1; # End of File::ConfigDir