889f28b0a3fcaa7892b7fba337b5671ad86bb593
[p5sagit/local-lib.git] / lib / local / lib.pm
1 use strict;
2 use warnings;
3
4 package local::lib;
5
6 use 5.008001; # probably works with earlier versions but I'm not supporting them
7               # (patches would, of course, be welcome)
8
9 use File::Spec ();
10 use File::Path ();
11 use Carp ();
12 use Config;
13
14 our $VERSION = '1.004006'; # 1.4.6
15 my @KNOWN_FLAGS = (qw/--self-contained/);
16
17 sub import {
18   my ($class, @args) = @_;
19   @args <= 1 + @KNOWN_FLAGS or die <<'DEATH';
20 Please see `perldoc local::lib` for directions on using this module.
21 DEATH
22
23   # Remember what PERL5LIB was when we started
24   my $perl5lib = $ENV{PERL5LIB};
25
26   my %arg_store;
27   for my $arg (@args) {
28     # check for lethal dash first to stop processing before causing problems
29     if ($arg =~ /−/) {
30       die <<'DEATH';
31 WHOA THERE! It looks like you've got some fancy dashes in your commandline!
32 These are *not* the traditional -- dashes that software recognizes. You
33 probably got these by copy-pasting from the perldoc for this module as
34 rendered by a UTF8-capable formatter. This most typically happens on an OS X
35 terminal, but can happen elsewhere too. Please try again after replacing the
36 dashes with normal minus signs.
37 DEATH
38     }
39     elsif(grep { $arg eq $_ } @KNOWN_FLAGS) {
40       (my $flag = $arg) =~ s/--//;
41       $arg_store{$flag} = 1;
42     }
43     elsif($arg =~ /^--/) {
44       die "Unknown import argument: $arg";
45     }
46     else {
47       # assume that what's left is a path
48       $arg_store{path} = $arg;
49     }
50   }
51
52   if($arg_store{'self-contained'}) {
53     # The only directories that remain are those that we just defined and those
54     # where core modules are stored.  We put PERL5LIB first, so it'll be favored
55     # over privlibexp and archlibexp
56     my %seen;
57     @INC = grep { ! $seen{$_}++ } (
58       $class->install_base_perl_path($arg_store{path}),
59       $class->install_base_arch_path($arg_store{path}),
60       split( $Config{path_sep}, $perl5lib ),
61       $Config::Config{privlibexp},
62       $Config::Config{archlibexp}
63   );
64     
65     # We explicitly set PERL5LIB here to the above de-duped list to prevent
66     # @INC from growing with each invocation 
67     $ENV{PERL5LIB} = join( $Config{path_sep}, @INC );
68   }
69
70   $arg_store{path} = $class->resolve_path($arg_store{path});
71   $class->setup_local_lib_for($arg_store{path});
72
73   for (@INC) { # Untaint @INC
74     next if ref; # Skip entry if it is an ARRAY, CODE, blessed, etc.
75     m/(.*)/ and $_ = $1;
76   }
77 }
78
79 sub pipeline;
80
81 sub pipeline {
82   my @methods = @_;
83   my $last = pop(@methods);
84   if (@methods) {
85     \sub {
86       my ($obj, @args) = @_;
87       $obj->${pipeline @methods}(
88         $obj->$last(@args)
89       );
90     };
91   } else {
92     \sub {
93       shift->$last(@_);
94     };
95   }
96 }
97
98 =begin testing
99
100 #:: test pipeline
101
102 package local::lib;
103
104 { package Foo; sub foo { -$_[1] } sub bar { $_[1]+2 } sub baz { $_[1]+3 } }
105 my $foo = bless({}, 'Foo');                                                 
106 Test::More::ok($foo->${pipeline qw(foo bar baz)}(10) == -15);
107
108 =end testing
109
110 =cut
111
112 sub resolve_path {
113   my ($class, $path) = @_;
114   $class->${pipeline qw(
115     resolve_relative_path
116     resolve_home_path
117     resolve_empty_path
118   )}($path);
119 }
120
121 sub resolve_empty_path {
122   my ($class, $path) = @_;
123   if (defined $path) {
124     $path;
125   } else {
126     '~/perl5';
127   }
128 }
129
130 =begin testing
131
132 #:: test classmethod setup
133
134 my $c = 'local::lib';
135
136 =end testing
137
138 =begin testing
139
140 #:: test classmethod
141
142 is($c->resolve_empty_path, '~/perl5');
143 is($c->resolve_empty_path('foo'), 'foo');
144
145 =end testing
146
147 =cut
148
149 sub resolve_home_path {
150   my ($class, $path) = @_;
151   return $path unless ($path =~ /^~/);
152   my ($user) = ($path =~ /^~([^\/]+)/); # can assume ^~ so undef for 'us'
153   my $tried_file_homedir;
154   my $homedir = do {
155     if (eval { require File::HomeDir } && $File::HomeDir::VERSION >= 0.65) {
156       $tried_file_homedir = 1;
157       if (defined $user) {
158         File::HomeDir->users_home($user);
159       } else {
160         File::HomeDir->my_home;
161       }
162     } else {
163       if (defined $user) {
164         (getpwnam $user)[7];
165       } else {
166         if (defined $ENV{HOME}) {
167           $ENV{HOME};
168         } else {
169           (getpwuid $<)[7];
170         }
171       }
172     }
173   };
174   unless (defined $homedir) {
175     Carp::croak(
176       "Couldn't resolve homedir for "
177       .(defined $user ? $user : 'current user')
178       .($tried_file_homedir ? '' : ' - consider installing File::HomeDir')
179     );
180   }
181   $path =~ s/^~[^\/]*/$homedir/;
182   $path;
183 }
184
185 sub resolve_relative_path {
186   my ($class, $path) = @_;
187   $path = File::Spec->rel2abs($path);
188 }
189
190 =begin testing
191
192 #:: test classmethod
193
194 local *File::Spec::rel2abs = sub { shift; 'FOO'.shift; };
195 is($c->resolve_relative_path('bar'),'FOObar');
196
197 =end testing
198
199 =cut
200
201 sub setup_local_lib_for {
202   my ($class, $path) = @_;
203   $path = $class->ensure_dir_structure_for($path);
204   if ($0 eq '-') {
205     $class->print_environment_vars_for($path);
206     exit 0;
207   } else {
208     $class->setup_env_hash_for($path);
209     unshift(@INC, split($Config{path_sep}, $ENV{PERL5LIB}));
210   }
211 }
212
213 sub modulebuildrc_path {
214   my ($class, $path) = @_;
215   File::Spec->catfile($path, '.modulebuildrc');
216 }
217
218 sub install_base_bin_path {
219   my ($class, $path) = @_;
220   File::Spec->catdir($path, 'bin');
221 }
222
223 sub install_base_perl_path {
224   my ($class, $path) = @_;
225   File::Spec->catdir($path, 'lib', 'perl5');
226 }
227
228 sub install_base_arch_path {
229   my ($class, $path) = @_;
230   File::Spec->catdir($class->install_base_perl_path($path), $Config{archname});
231 }
232
233 sub ensure_dir_structure_for {
234   my ($class, $path) = @_;
235   unless (-d $path) {
236     warn "Attempting to create directory ${path}\n";
237   }
238   File::Path::mkpath($path);
239   # Need to have the path exist to make a short name for it, so
240   # converting to a short name here.
241   $path = Win32::GetShortPathName($path) if $^O eq 'MSWin32';
242   my $modulebuildrc_path = $class->modulebuildrc_path($path);
243   if (-e $modulebuildrc_path) {
244     unless (-f _) {
245       Carp::croak("${modulebuildrc_path} exists but is not a plain file");
246     }
247   } else {
248     warn "Attempting to create file ${modulebuildrc_path}\n";
249     open MODULEBUILDRC, '>', $modulebuildrc_path
250       || Carp::croak("Couldn't open ${modulebuildrc_path} for writing: $!");
251     print MODULEBUILDRC qq{install  --install_base  ${path}\n}
252       || Carp::croak("Couldn't write line to ${modulebuildrc_path}: $!");
253     close MODULEBUILDRC
254       || Carp::croak("Couldn't close file ${modulebuildrc_path}: $@");
255   }
256
257   return $path;
258 }
259
260 sub INTERPOLATE_ENV () { 1 }
261 sub LITERAL_ENV     () { 0 }
262
263 sub print_environment_vars_for {
264   my ($class, $path) = @_;
265   my @envs = $class->build_environment_vars_for($path, LITERAL_ENV);
266   my $out = '';
267
268   # rather basic csh detection, goes on the assumption that something won't
269   # call itself csh unless it really is. also, default to bourne in the
270   # pathological situation where a user doesn't have $ENV{SHELL} defined.
271   # note also that shells with funny names, like zoid, are assumed to be
272   # bourne.
273   my $shellbin = 'sh';
274   if(defined $ENV{'SHELL'}) {
275       my @shell_bin_path_parts = File::Spec->splitpath($ENV{'SHELL'});
276       $shellbin = $shell_bin_path_parts[-1];
277   }
278   my $shelltype = do {
279       local $_ = $shellbin;
280       if(/csh/) {
281           'csh'
282       } else {
283           'bourne'
284       }
285   };
286
287   # Both Win32 and Cygwin have $ENV{COMSPEC} set.
288   if (defined $ENV{'COMSPEC'} && $^O ne 'cygwin') {
289       my @shell_bin_path_parts = File::Spec->splitpath($ENV{'COMSPEC'});
290       $shellbin = $shell_bin_path_parts[-1];
291          $shelltype = do {
292                  local $_ = $shellbin;
293                  if(/command\.com/) {
294                          'win32'
295                  } elsif(/cmd\.exe/) {
296                          'win32'
297                  } elsif(/4nt\.exe/) {
298                          'win32'
299                  } else {
300                          $shelltype
301                  }
302          };
303   }
304
305   while (@envs) {
306     my ($name, $value) = (shift(@envs), shift(@envs));
307     $value =~ s/(\\")/\\$1/g;
308     $out .= $class->${\"build_${shelltype}_env_declaration"}($name, $value);
309   }
310   print $out;
311 }
312
313 # simple routines that take two arguments: an %ENV key and a value. return
314 # strings that are suitable for passing directly to the relevant shell to set
315 # said key to said value.
316 sub build_bourne_env_declaration {
317   my $class = shift;
318   my($name, $value) = @_;
319   return qq{export ${name}="${value}"\n};
320 }
321
322 sub build_csh_env_declaration {
323   my $class = shift;
324   my($name, $value) = @_;
325   return qq{setenv ${name} "${value}"\n};
326 }
327
328 sub build_win32_env_declaration {
329   my $class = shift;
330   my($name, $value) = @_;
331   return qq{set ${name}=${value}\n};
332 }
333
334 sub setup_env_hash_for {
335   my ($class, $path) = @_;
336   my %envs = $class->build_environment_vars_for($path, INTERPOLATE_ENV);
337   @ENV{keys %envs} = values %envs;
338 }
339
340 sub build_environment_vars_for {
341   my ($class, $path, $interpolate) = @_;
342   return (
343     MODULEBUILDRC => $class->modulebuildrc_path($path),
344     PERL_MM_OPT => "INSTALL_BASE=${path}",
345     PERL5LIB => join($Config{path_sep},
346                   $class->install_base_perl_path($path),
347                   $class->install_base_arch_path($path),
348                   ($ENV{PERL5LIB} ?
349                     ($interpolate == INTERPOLATE_ENV
350                       ? ($ENV{PERL5LIB})
351                       : (($^O ne 'MSWin32') ? '$PERL5LIB' : '%PERL5LIB%' ))
352                     : ())
353                 ),
354     PATH => join($Config{path_sep},
355               $class->install_base_bin_path($path),
356               ($interpolate == INTERPOLATE_ENV
357                 ? $ENV{PATH}
358                 : (($^O ne 'MSWin32') ? '$PATH' : '%PATH%' ))
359              ),
360   )
361 }
362
363 =begin testing
364
365 #:: test classmethod
366
367 File::Path::rmtree('t/var/splat');
368
369 $c->ensure_dir_structure_for('t/var/splat');
370
371 ok(-d 't/var/splat');
372
373 ok(-f 't/var/splat/.modulebuildrc');
374
375 =end testing
376
377 =head1 NAME
378
379 local::lib - create and use a local lib/ for perl modules with PERL5LIB
380
381 =head1 SYNOPSIS
382
383 In code -
384
385   use local::lib; # sets up a local lib at ~/perl5
386
387   use local::lib '~/foo'; # same, but ~/foo
388
389   # Or...
390   use FindBin;
391   use local::lib "$FindBin::Bin/../support";  # app-local support library
392
393 From the shell -
394
395   # Install LWP and it's missing dependencies to the 'my_lwp' directory
396   perl -MCPAN -Mlocal::lib=my_lwp -e 'CPAN::install(LWP)'
397
398   # Install LWP and *all non-core* dependencies to the 'my_lwp' directory 
399   perl -MCPAN -Mlocal::lib=--self-contained,my_lwp -e 'CPAN::install(LWP)'
400
401   # Just print out useful shell commands
402   $ perl -Mlocal::lib
403   export MODULEBUILDRC=/home/username/perl/.modulebuildrc
404   export PERL_MM_OPT='INSTALL_BASE=/home/username/perl'
405   export PERL5LIB='/home/username/perl/lib/perl5:/home/username/perl/lib/perl5/i386-linux'
406   export PATH="/home/username/perl/bin:$PATH"
407
408 To bootstrap if you don't have local::lib itself installed -
409
410   <download local::lib tarball from CPAN, unpack and cd into dir>
411
412   $ perl Makefile.PL --bootstrap
413   $ make test && make install
414
415   $ echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >>~/.bashrc
416
417   # Or for C shells...
418
419   $ /bin/csh
420   % echo $SHELL
421   /bin/csh
422   % perl -I$HOME/perl5/lib/perl5 -Mlocal::lib >> ~/.cshrc
423
424 You can also pass --bootstrap=~/foo to get a different location -
425
426   $ perl Makefile.PL --bootstrap=~/foo
427   $ make test && make install
428
429   $ echo 'eval $(perl -I$HOME/foo/lib/perl5 -Mlocal::lib=$HOME/foo)' >>~/.bashrc
430
431 If you're on a slower machine, or are operating under draconian disk space
432 limitations, you can disable the automatic generation of manpages from POD when
433 installing modules by using the C<--no-manpages> argument when bootstrapping:
434
435   $ perl Makefile.PL --bootstrap --no-manpages
436
437 If you want to install multiple Perl module environments, say for application evelopment, 
438 install local::lib globally and then:
439
440     $ cd ~/mydir1
441     $ perl -Mlocal::lib=./
442     $ eval $(perl -Mlocal::lib=./)  ### To set the environment for this shell alone
443     $ printenv  ### You will see that ~/mydir1 is in the PERL5LIB
444     $ perl -MCPAN -e install ...    ### whatever modules you want
445     $ cd ../mydir2
446     ... REPEAT ...
447
448 For multiple environments for multiple apps you may need to include a modified version of 
449 the C<< use FindBin >> instructions in the "In code" sample above. If you did something like
450 the above, you have a set of Perl modules at C<< ~/mydir1/lib >>. If you have a script at
451 C<< ~/mydir1/scripts/myscript.pl >>, you need to tell it where to find the modules you installed 
452 for it at C<< ~/mydir1/lib >>.
453
454 In C<< ~/mydir1/scripts/myscript.pl >>:
455
456     use strict;
457     use warnings;
458     use local::lib "$FindBin::Bin/..";  ### points to ~/mydir1 and local::lib finds lib
459     use lib "$FindBin::Bin/../lib";     ### points to ~/mydir1/lib
460
461 Put this before any BEGIN { ... } blocks that require the modules you installed.
462
463 =head2 Differences when using this module under Win32
464
465     C:\>perl -Mlocal::lib
466     set MODULEBUILDRC=C:\DOCUME~1\ADMINI~1\perl5\.modulebuildrc
467     set PERL_MM_OPT=INSTALL_BASE=C:\DOCUME~1\ADMINI~1\perl5
468     set PERL5LIB=C:\DOCUME~1\ADMINI~1\perl5\lib\perl5;C:\DOCUME~1\ADMINI~1\perl5\lib\perl5\MSWin32-x86-multi-thread
469     set PATH=C:\DOCUME~1\ADMINI~1\perl5\bin;%PATH%
470
471        ### To set the environment for this shell alone
472     C:\>perl -Mlocal::lib > %TEMP%\tmp.bat && %TEMP%\tmp.bat && del %TEMP%\temp.bat
473     ### instead of $(perl -Mlocal::lib=./)
474
475 If you want the environment entries to persist, you'll need to add then to the
476 Control Panel's System applet yourself at the moment.
477
478 The "~" is translated to the user's profile directory (the directory named for
479 the user under "Documents and Settings" (Windows XP or earlier) or "Users"
480 (Windows Vista or later) unless $ENV{HOME} exists. After that, the home
481 directory is translated to a short name (which means the directory must exist)
482 and the subdirectories are created.
483
484 =head1 DESCRIPTION
485
486 This module provides a quick, convenient way of bootstrapping a user-local Perl
487 module library located within the user's home directory. It also constructs and
488 prints out for the user the list of environment variables using the syntax
489 appropriate for the user's current shell (as specified by the C<SHELL>
490 environment variable), suitable for directly adding to one's shell configuration
491 file.
492
493 More generally, local::lib allows for the bootstrapping and usage of a directory
494 containing Perl modules outside of Perl's C<@INC>. This makes it easier to ship
495 an application with an app-specific copy of a Perl module, or collection of
496 modules. Useful in cases like when an upstream maintainer hasn't applied a patch
497 to a module of theirs that you need for your application.
498
499 On import, local::lib sets the following environment variables to appropriate
500 values:
501
502 =over 4
503
504 =item MODULEBUILDRC
505
506 =item PERL_MM_OPT
507
508 =item PERL5LIB
509
510 =item PATH
511
512 PATH is appended to, rather than clobbered.
513
514 =back
515
516 These values are then available for reference by any code after import.
517
518 =head1 METHODS
519
520 =head2 ensure_directory_structure_for
521
522 =over 4
523
524 =item Arguments: path
525
526 =back
527
528 Attempts to create the given path, and all required parent directories. Throws
529 an exception on failure.
530
531 =head2 print_environment_vars_for
532
533 =over 4
534
535 =item Arguments: path
536
537 =back
538
539 Prints to standard output the variables listed above, properly set to use the
540 given path as the base directory.
541
542 =head2 setup_env_hash_for
543
544 =over 4
545
546 =item Arguments: path
547
548 =back
549
550 Constructs the C<%ENV> keys for the given path, by calling
551 C<build_environment_vars_for>.
552
553 =head2 install_base_perl_path
554
555 =over 4
556
557 =item Arguments: path
558
559 =back
560
561 Returns a path describing where to install the Perl modules for this local
562 library installation. Appends the directories C<lib> and C<perl5> to the given
563 path.
564
565 =head2 install_base_arch_path
566
567 =over 4
568
569 =item Arguments: path
570
571 =back
572
573 Returns a path describing where to install the architecture-specific Perl
574 modules for this local library installation. Based on the
575 L</install_base_perl_path> method's return value, and appends the value of
576 C<$Config{archname}>.
577
578 =head2 install_base_bin_path
579
580 =over 4
581
582 =item Arguments: path
583
584 =back
585
586 Returns a path describing where to install the executable programs for this
587 local library installation. Based on the L</install_base_perl_path> method's
588 return value, and appends the directory C<bin>.
589
590 =head2 modulebuildrc_path
591
592 =over 4
593
594 =item Arguments: path
595
596 =back
597
598 Returns a path describing where to install the C<.modulebuildrc> file, based on
599 the given path.
600
601 =head2 resolve_empty_path
602
603 =over 4
604
605 =item Arguments: path
606
607 =back
608
609 Builds and returns the base path into which to set up the local module
610 installation. Defaults to C<~/perl5>.
611
612 =head2 resolve_home_path
613
614 =over 4
615
616 =item Arguments: path
617
618 =back
619
620 Attempts to find the user's home directory. If installed, uses C<File::HomeDir>
621 for this purpose. If no definite answer is available, throws an exception.
622
623 =head2 resolve_relative_path
624
625 =over 4
626
627 =item Arguments: path
628
629 =back
630
631 Translates the given path into an absolute path.
632
633 =head2 resolve_path
634
635 =over 4
636
637 =item Arguments: path
638
639 =back
640
641 Calls the following in a pipeline, passing the result from the previous to the
642 next, in an attempt to find where to configure the environment for a local
643 library installation: L</resolve_empty_path>, L</resolve_home_path>,
644 L</resolve_relative_path>. Passes the given path argument to
645 L</resolve_empty_path> which then returns a result that is passed to
646 L</resolve_home_path>, which then has its result passed to
647 L</resolve_relative_path>. The result of this final call is returned from
648 L</resolve_path>.
649
650 =head1 A WARNING ABOUT UNINST=1
651
652 Be careful about using local::lib in combination with "make install UNINST=1".
653 The idea of this feature is that will uninstall an old version of a module
654 before installing a new one. However it lacks a safety check that the old
655 version and the new version will go in the same directory. Used in combination
656 with local::lib, you can potentially delete a globally accessible version of a
657 module while installing the new version in a local place. Only combine "make
658 install UNINST=1" and local::lib if you understand these possible consequences.
659
660 =head1 LIMITATIONS
661
662 Rather basic shell detection. Right now anything with csh in its name is
663 assumed to be a C shell or something compatible, and everything else is assumed
664 to be Bourne, except on Win32 systems. If the C<SHELL> environment variable is
665 not set, a Bourne-compatible shell is assumed.
666
667 Bootstrap is a hack and will use CPAN.pm for ExtUtils::MakeMaker even if you
668 have CPANPLUS installed.
669
670 Kills any existing PERL5LIB, PERL_MM_OPT or MODULEBUILDRC.
671
672 Should probably auto-fixup CPAN config if not already done.
673
674 Patches very much welcome for any of the above.
675
676 On Win32 systems, does not have a way to write the created environment variables
677 to the registry, so that they can persist through a reboot.
678
679 =head1 TROUBLESHOOTING
680
681 If you've configured local::lib to install CPAN modules somewhere in to your
682 home directory, and at some point later you try to install a module with C<cpan
683 -i Foo::Bar>, but it fails with an error like: C<Warning: You do not have
684 permissions to install into /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux at
685 /usr/lib64/perl5/5.8.8/Foo/Bar.pm> and buried within the install log is an
686 error saying C<'INSTALL_BASE' is not a known MakeMaker parameter name>, then
687 you've somehow lost your updated ExtUtils::MakeMaker module.
688
689 To remedy this situation, rerun the bootstrapping procedure documented above.
690
691 Then, run C<rm -r ~/.cpan/build/Foo-Bar*>
692
693 Finally, re-run C<cpan -i Foo::Bar> and it should install without problems.
694
695 =head1 ENVIRONMENT
696
697 =over 4
698
699 =item SHELL
700
701 =item COMSPEC
702
703 local::lib looks at the user's C<SHELL> environment variable when printing out
704 commands to add to the shell configuration file.
705
706 On Win32 systems, C<COMSPEC> is also examined.
707
708 =back
709
710 =head1 AUTHOR
711
712 Matt S Trout <mst@shadowcat.co.uk> http://www.shadowcat.co.uk/
713
714 auto_install fixes kindly sponsored by http://www.takkle.com/
715
716 =head1 CONTRIBUTORS
717
718 Patches to correctly output commands for csh style shells, as well as some
719 documentation additions, contributed by Christopher Nehren <apeiron@cpan.org>.
720
721 '--self-contained' feature contributed by Mark Stosberg <mark@summersault.com>.
722
723 Ability to pass '--self-contained' without a directory inspired by frew on
724 irc.perl.org/#catalyst.
725
726 Doc patches for a custom local::lib directory contributed by Torsten Raudssus
727 <torsten@raudssus.de>.
728
729 Hans Dieter Pearcey <hdp@cpan.org> sent in some additional tests for ensuring
730 things will install properly, submitted a fix for the bug causing problems with
731 writing Makefiles during bootstrapping, contributed an example program, and
732 submitted yet another fix to ensure that local::lib can install and bootstrap
733 properly. Many, many thanks!
734
735 pattern of Freenode IRC contributed the beginnings of the Troubleshooting
736 section. Many thanks!
737
738 Patch to add Win32 support contributed by Curtis Jewell <csjewell@cpan.org>.
739
740 =head1 LICENSE
741
742 This library is free software under the same license as perl itself.
743
744 =cut
745
746 1;