1 package File::ShareDir;
7 File::ShareDir - Locate per-dist and per-module shared files
11 use File::ShareDir ':ALL';
13 # Where are distribution-level shared data files kept
14 $dir = dist_dir('File-ShareDir');
16 # Where are module-level shared data files kept
17 $dir = module_dir('File::ShareDir');
19 # Find a specific file in our dist/module shared dir
20 $file = dist_file( 'File-ShareDir', 'file/name.txt');
21 $file = module_file('File::ShareDir', 'file/name.txt');
23 # Like module_file, but search up the inheritance tree
24 $file = class_file( 'Foo::Bar', 'file/name.txt' );
28 The intent of L<File::ShareDir> is to provide a companion to
29 L<Class::Inspector> and L<File::HomeDir>, modules that take a
30 process that is well-known by advanced Perl developers but gets a
31 little tricky, and make it more available to the larger Perl community.
33 Quite often you want or need your Perl module (CPAN or otherwise)
34 to have access to a large amount of read-only data that is stored
35 on the file-system at run-time.
37 On a linux-like system, this would be in a place such as /usr/share,
38 however Perl runs on a wide variety of different systems, and so
39 the use of any one location is unreliable.
41 Perl provides a little-known method for doing this, but almost
42 nobody is aware that it exists. As a result, module authors often
43 go through some very strange ways to make the data available to
46 The most common of these is to dump the data out to an enormous
47 Perl data structure and save it into the module itself. The
48 result are enormous multi-megabyte .pm files that chew up a
49 lot of memory needlessly.
51 Another method is to put the data "file" after the __DATA__ compiler
52 tag and limit yourself to access as a filehandle.
54 The problem to solve is really quite simple.
56 1. Write the data files to the system at install time.
58 2. Know where you put them at run-time.
60 Perl's install system creates an "auto" directory for both
61 every distribution and for every module file.
63 These are used by a couple of different auto-loading systems
64 to store code fragments generated at install time, and various
65 other modules written by the Perl "ancient masters".
67 But the same mechanism is available to any dist or module to
68 store any sort of data.
70 =head2 Using Data in your Module
72 C<File::ShareDir> forms one half of a two part solution.
74 Once the files have been installed to the correct directory,
75 you can use C<File::ShareDir> to find your files again after
78 For the installation half of the solution, see L<Module::Install>
79 and its C<install_share> directive.
83 C<File::ShareDir> provides four functions for locating files and
86 For greater maintainability, none of these are exported by default
87 and you are expected to name the ones you want at use-time, or provide
88 the C<':ALL'> tag. All of the following are equivalent.
90 # Load but don't import, and then call directly
92 $dir = File::ShareDir::dist_dir('My-Dist');
94 # Import a single function
95 use File::ShareDir 'dist_dir';
98 # Import all the functions
99 use File::ShareDir ':ALL';
102 All of the functions will check for you that the dir/file actually
103 exists, and that you have read permissions, or they will throw an
114 use Params::Util '_CLASS';
115 use Class::Inspector ();
117 use vars qw{$VERSION @ISA @EXPORT_OK %EXPORT_TAGS};
120 @ISA = qw{ Exporter };
123 module_dir module_file
127 ALL => [ @EXPORT_OK ],
131 use constant IS_MACOS => !!($^O eq 'MacOS');
137 #####################################################################
138 # Interface Functions
144 # Get a distribution's shared files directory
145 my $dir = dist_dir('My-Distribution');
147 The C<dist_dir> function takes a single parameter of the name of an
148 installed (CPAN or otherwise) distribution, and locates the shared
149 data directory created at install time for it.
151 Returns the directory path as a string, or dies if it cannot be
152 located or is not readable.
157 my $dist = _DIST(shift);
160 # Try the new version
161 $dir = _dist_dir_new( $dist );
162 return $dir if defined $dir;
164 # Fall back to the legacy version
165 $dir = _dist_dir_old( $dist );
166 return $dir if defined $dir;
169 croak("Failed to find share dir for dist '$dist'");
176 my $path = File::Spec->catdir(
177 'auto', 'share', 'dist', $dist,
180 # Find the full dir withing @INC
181 foreach my $inc ( @INC ) {
182 next unless defined $inc and ! ref $inc;
183 my $dir = File::Spec->catdir( $inc, $path );
186 croak("Found directory '$dir', but no read permissions");
198 my $path = File::Spec->catdir(
199 'auto', split( /-/, $dist ),
202 # Find the full dir within @INC
203 foreach my $inc ( @INC ) {
204 next unless defined $inc and ! ref $inc;
205 my $dir = File::Spec->catdir( $inc, $path );
208 croak("Found directory '$dir', but no read permissions");
220 # Get a module's shared files directory
221 my $dir = module_dir('My::Module');
223 The C<module_dir> function takes a single parameter of the name of an
224 installed (CPAN or otherwise) module, and locates the shared data
225 directory created at install time for it.
227 In order to find the directory, the module B<must> be loaded when
228 calling this function.
230 Returns the directory path as a string, or dies if it cannot be
231 located or is not readable.
236 my $module = _MODULE(shift);
239 # Try the new version
240 $dir = _module_dir_new( $module );
241 return $dir if defined $dir;
243 # Fall back to the legacy version
244 return _module_dir_old( $module );
247 sub _module_dir_new {
251 my $path = File::Spec->catdir(
252 'auto', 'share', 'module',
253 _module_subdir( $module ),
256 # Find the full dir withing @INC
257 foreach my $inc ( @INC ) {
258 next unless defined $inc and ! ref $inc;
259 my $dir = File::Spec->catdir( $inc, $path );
262 croak("Found directory '$dir', but no read permissions");
270 sub _module_dir_old {
272 my $short = Class::Inspector->filename($module);
273 my $long = Class::Inspector->loaded_filename($module);
274 $short =~ tr{/}{:} if IS_MACOS;
275 substr( $short, -3, 3, '' );
276 $long =~ m/^(.*)\Q$short\E\.pm\z/s or die("Failed to find base dir");
277 my $dir = File::Spec->catdir( "$1", 'auto', $short );
279 croak("Directory '$dir', does not exist");
282 croak("Directory '$dir', no read permissions");
291 # Find a file in our distribution shared dir
292 my $dir = dist_file('My-Distribution', 'file/name.txt');
294 The C<dist_file> function takes two params of the distribution name
295 and file name, locates the dist dir, and then finds the file within
296 it, verifying that the file actually exists, and that it is readable.
298 The filename should be a relative path in the format of your local
299 filesystem. It will simply added to the directory using L<File::Spec>'s
302 Returns the file path as a string, or dies if the file or the dist's
303 directory cannot be located, or the file is not readable.
308 my $dist = _DIST(shift);
309 my $file = _FILE(shift);
311 # Try the new version first
312 my $path = _dist_file_new( $dist, $file );
313 return $path if defined $path;
315 # Hand off to the legacy version
316 return _dist_file_old( $dist, $file );;
323 # If it exists, what should the path be
324 my $dir = _dist_dir_new( $dist );
325 my $path = File::Spec->catfile( $dir, $file );
327 # Does the file exist
328 return undef unless -e $path;
329 unless ( -f $path ) {
330 croak("Found dist_file '$path', but not a file");
332 unless ( -r $path ) {
333 croak("File '$path', no read permissions");
344 my $path = File::Spec->catfile(
345 'auto', split( /-/, $dist ), $file,
348 # Find the full dir withing @INC
349 foreach my $inc ( @INC ) {
350 next unless defined $inc and ! ref $inc;
351 my $full = File::Spec->catdir( $inc, $path );
352 next unless -e $full;
353 unless ( -r $full ) {
354 croak("Directory '$full', no read permissions");
360 croak("Failed to find shared file '$file' for dist '$dist'");
367 # Find a file in our module shared dir
368 my $dir = module_file('My::Module', 'file/name.txt');
370 The C<module_file> function takes two params of the module name
371 and file name. It locates the module dir, and then finds the file within
372 it, verifying that the file actually exists, and that it is readable.
374 In order to find the directory, the module B<must> be loaded when
375 calling this function.
377 The filename should be a relative path in the format of your local
378 filesystem. It will simply added to the directory using L<File::Spec>'s
381 Returns the file path as a string, or dies if the file or the dist's
382 directory cannot be located, or the file is not readable.
387 my $module = _MODULE(shift);
388 my $file = _FILE(shift);
389 my $dir = module_dir($module);
390 my $path = File::Spec->catfile($dir, $file);
391 unless ( -e $path ) {
392 croak("File '$file' does not exist in module dir");
394 unless ( -r $path ) {
395 croak("File '$file' cannot be read, no read permissions");
404 # Find a file in our module shared dir, or in our parent class
405 my $dir = class_file('My::Module', 'file/name.txt');
407 The C<module_file> function takes two params of the module name
408 and file name. It locates the module dir, and then finds the file within
409 it, verifying that the file actually exists, and that it is readable.
411 In order to find the directory, the module B<must> be loaded when
412 calling this function.
414 The filename should be a relative path in the format of your local
415 filesystem. It will simply added to the directory using L<File::Spec>'s
418 If the file is NOT found for that module, C<class_file> will scan up
419 the module's @ISA tree, looking for the file in all of the parent
422 This allows you to, in effect, "subclass" shared files.
424 Returns the file path as a string, or dies if the file or the dist's
425 directory cannot be located, or the file is not readable.
430 my $module = _MODULE(shift);
431 my $file = _FILE(shift);
433 # Get the super path ( not including UNIVERSAL )
434 # Rather than using Class::ISA, we'll use an inlined version
435 # that implements the same basic algorithm.
437 my @queue = ( $module );
438 my %seen = ( $module => 1 );
439 while ( my $cl = shift @queue ) {
442 unshift @queue, grep { ! $seen{$_}++ }
443 map { s/^::/main::/; s/\'/::/g; $_ }
448 foreach my $class ( @path ) {
454 my $path = File::Spec->catfile($dir, $file);
455 unless ( -e $path ) {
458 unless ( -r $path ) {
459 croak("File '$file' cannot be read, no read permissions");
463 croak("File '$file' does not exist in class or parent shared files");
469 #####################################################################
480 my @dirs = grep { -e } ( $Config::Config{archlibexp}, $Config::Config{sitearchexp} );
481 my $file = File::Spec->catfile(
482 'auto', split( /::/, $module), '.packlist',
485 foreach my $dir ( @dirs ) {
486 my $path = File::Spec->catfile( $dir, $file );
487 next unless -f $path;
490 my $packlist = ExtUtils::Packlist->new($path);
491 unless ( $packlist ) {
492 die "Failed to load .packlist file for $module";
495 die "CODE INCOMPLETE";
498 die "CODE INCOMPLETE";
501 # Matches a valid distribution name
502 ### This is a total guess at this point
504 if ( defined $_[0] and ! ref $_[0] and $_[0] =~ /^[a-z0-9+_-]+$/is ) {
507 croak("Not a valid distribution name");
510 # A valid and loaded module name
512 my $module = _CLASS(shift) or croak("Not a valid module name");
513 if ( Class::Inspector->loaded($module) ) {
516 croak("Module '$module' is not loaded");
522 unless ( defined $file and ! ref $file and length $file ) {
523 croak("Did not pass a file name");
525 if ( File::Spec->file_name_is_absolute($file) ) {
526 croak("Cannot use absolute file name '$file'");
537 Bugs should always be submitted via the CPAN bug tracker
539 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=File-ShareDir>
541 For other issues, contact the maintainer.
545 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
549 L<File::HomeDir>, L<Module::Install>, L<Module::Install::Share>,
550 L<File::ShareDir::PAR>
554 Copyright 2005 - 2009 Adam Kennedy.
556 This program is free software; you can redistribute
557 it and/or modify it under the same terms as Perl itself.
559 The full text of the license can be found in the
560 LICENSE file included with this module.