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