File Coverage

blib/lib/App/local/lib/helper.pm
Criterion Covered Total %
statement 12 65 18.4
branch 0 10 0.0
condition 0 6 0.0
subroutine 4 17 23.5
pod 0 6 0.0
total 16 104 15.3


line stmt bran cond sub pod time code
1             package App::local::lib::helper;
2              
3 1     1   1184 use strict;
  1         3  
  1         41  
4 1     1   5 use warnings;
  1         3  
  1         30  
5 1     1   15 use File::Spec;
  1         1  
  1         24  
6              
7 1     1   25 use 5.008005;
  1         3  
  1         1185  
8             our $VERSION = '0.07';
9              
10             sub run {
11 0     0 0   my ($class, %opts) = @_;
12 0           my $local_lib_helper = __PACKAGE__->new(%opts);
13 0           return $local_lib_helper->create_local_lib_helper;
14             }
15              
16             sub _diag {
17 0     0     my $self = shift @_;
18 0           print STDERR @_, "\n";
19             }
20              
21             sub diag {
22 0     0 0   shift->_diag(@_);
23             }
24              
25             sub error {
26 0     0 0   shift->_diag(@_);
27 0           die "Exiting with Errors";
28             }
29              
30             sub new {
31 0     0 0   my ($class, %opts) = @_;
32 0           return bless \%opts, $class;
33             }
34              
35             sub create_local_lib_helper {
36 0     0 0   my $self = shift;
37 0 0         if (my $target = $self->{target}) {
    0          
38 0           return $self->_create_local_lib_helper($target);
39             } elsif ($self->has_local_lib_env) {
40 0           my ($install_base, $target) =
41 0           map {split '=', $_}
42 0           grep { m/^INSTALL_BASE/ }
43             split ' ', $ENV{PERL_MM_OPT};
44 0           $self->diag("My target local::lib is $target");
45 0           $self->_create_local_lib_helper_bashrc($target);
46 0           $self->_create_local_lib_helper_cshrc($target);
47 0           $self->_create_local_lib_helper_relative($target);
48 0           $self->_create_local_lib_helper($target);
49 0           return 1;
50             }
51              
52 0           $self->diag(<
53             !
54             ! You are not installing the helper script while in a local::lib context nor
55             ! have you specified the local::lib target directory via the --local_lib
56             ! commandline option. I don't know how to install the helper script.
57             !
58             DIAG
59             }
60              
61             sub has_local_lib_env {
62 0 0 0 0 0   if(
      0        
63             $ENV{PERL_MM_OPT} and
64             ($ENV{MODULEBUILDRC} or $ENV{PERL_MB_OPT})
65             ) {
66 0           return 1;
67             } else {
68 0           return;
69             }
70             }
71              
72             sub _create_file {
73 0     0     my ($self, $filename, $permissions, $text) = @_;
74 0 0         open (my $fh, '>', $filename)
75             || $self->error("Can't open $filename", $!);
76              
77 0           print $fh $text;
78              
79 0           close($fh);
80 0           chmod oct($permissions), $filename;
81 0           return $filename;
82             }
83              
84             sub _find_or_create_lib_bindir_from {
85 0     0     my ($self, $target) = @_;
86 0           my $lib = File::Spec->catdir($target, 'lib', 'perl5');
87 0           my $bindir = File::Spec->catdir($target, 'bin');
88 0 0         mkdir $bindir unless(-e $bindir);
89 0           return ($lib, $bindir);
90             }
91              
92             sub _create_local_lib_helper {
93 0     0     my ($self, $target) = @_;
94 0           my ($lib, $bindir) = $self->_find_or_create_lib_bindir_from($target);
95 0           my $bin = File::Spec->catdir($bindir, $self->{helper_name});
96 0           $self->_create_file($bin, $self->{helper_permissions}, <
97             #!$self->{which_perl}
98              
99             use strict;
100             use warnings;
101              
102             use lib '$lib';
103             use local::lib '$target';
104              
105             unless ( caller ) {
106             if ( \@ARGV ) {
107             exec \@ARGV;
108             }
109             }
110             END
111              
112             }
113              
114             sub _create_local_lib_helper_relative {
115 0     0     my ($self, $target) = @_;
116 0           my ($lib, $bindir) = $self->_find_or_create_lib_bindir_from($target);
117 0           my $bin = File::Spec->catdir($bindir, $self->{helper_name}.'-relative');
118 0           $self->_create_file($bin, $self->{helper_permissions}, <
119             #!/usr/bin/env perl
120              
121             use strict;
122             use warnings;
123              
124             use FindBin;
125             use File::Spec;
126             use lib File::Spec->catdir(\$FindBin::Bin, '..', 'lib', 'perl5');
127             use local::lib File::Spec->catdir(\$FindBin::Bin, '..');
128              
129             unless ( caller ) {
130             if ( \@ARGV ) {
131             exec \@ARGV;
132             }
133             }
134             END
135              
136             }
137              
138             sub _create_local_lib_helper_bashrc {
139 0     0     my ($self, $target) = @_;
140 0           my ($lib, $bindir) = $self->_find_or_create_lib_bindir_from($target);
141 0           my $bin = File::Spec->catdir($bindir, $self->{helper_name}.'-bashrc');
142 0           $self->_create_file($bin, $self->{helper_permissions}, <
143             eval \$($self->{which_perl} -I$lib -Mlocal::lib=$target)
144             END
145              
146             }
147              
148             sub _create_local_lib_helper_cshrc {
149 0     0     my ($self, $target) = @_;
150 0           my ($lib, $bindir) = $self->_find_or_create_lib_bindir_from($target);
151 0           my $bin = File::Spec->catdir($bindir, $self->{helper_name}.'-cshrc');
152 0           $self->_create_file($bin, $self->{helper_permissions}, <
153             $self->{which_perl} -I$lib -Mlocal::lib=$target
154             END
155              
156             }
157              
158             1;
159              
160             =head1 NAME
161              
162             App::local::lib::helper - Make it easy to run code against a local-lib
163              
164             =head1 SYNOPSIS
165              
166             Installing and using the helper (common usage)
167              
168             cpanm --local-lib ~/mylib App::local::lib::helper
169             ~/mylib/bin/localenv bash
170              
171             Customizing the helper creation (advanced use only)
172              
173             use App::local::lib::helper;
174             App::local::lib::helper->run(%opts);
175              
176             Note, if you don't have C already installed you can use the web service
177             version like so instead for all examples:
178              
179             curl -L http://cpanmin.us/ | perl - --local-lib ~/mylib App::local::lib::helper
180              
181             =head1 DESCRIPTION
182              
183             This is an object which provide the functionality to create a L
184             'helper' script in either the currently loaded L environment or in
185             a target directory of choice. By default the script is called C and
186             can be used to invoke a command under the L which it was built
187             against. For example, assume you build a L like so:
188              
189             cpanm --local-lib ~/mylib App::local::lib::helper
190              
191             Note what is happening. First, you are telling cpanminus to install everything
192             to a local::lib directory called C<~/mylib> (cpanminus behind the scenes uses
193             L to do this for you) then you are telling cpanminus to install the
194             distribution L into that created L directory.
195             When the C script for L runs, it notices
196             the fact that it is being asked to install into a locally lib managed directory
197             and will additionally generate a helper script into C<~/mylib/bin> called C.
198              
199             Now, if you want to invoke a perl application and use libs installed into
200             C<~/mylib>, you can do so like:
201              
202             ~/mylib/bin/localenv perl [SOME COMMAND]
203              
204             The command C will make sure the same L that was active
205             when L was originally installed is again installed
206             into the environment before executing the commands passed in C<@ARGV>. Upon
207             completing the command, the C<%ENV> is restored so that you can use this to fire
208             off an application against a specific L without needing to deal
209             with the details of how to activate the L or how to make sure
210             your C<%ENV> stays clean.
211              
212             The arguments given to C don't need to be a perl application. For
213             example, I often like to open a sub shell under a particular L
214             managed directory.
215              
216             ~/mylib/bin/localenv bash
217              
218             Now, if I do:
219              
220             perl -V
221              
222             I'll see that iC<~/mylib> has been added to C<@INC>. Additionally, C<~/mylib/bin> will
223             have been added to C<$PATH>, so that any command line perl applications installed
224             into the L (such as C or C) can be accessed easily.
225              
226             Another example usage would be when you want to install an application from
227             CPAN, install it and all its dependencies to a single directory root and
228             then run it without a lot of effort. For example:
229              
230             cpanm --local-lib ~/gitalyst-libs Gitalist App::local::lib::helper
231             ~/gitalyst-libs/bin/localenv gitalyst-server.pl
232              
233             And presto! Your cpan installed application is running, fully self-contained to
234             one root directory all under regular user privileges.
235              
236             L does all the real work, but I find this to be the easiest way to
237             run given code against a L root.
238              
239             =head2 Additional Helpers
240              
241             In addition to the C script which is documented above, we also create
242             two snippets of code suitable for including in your C<.bashrc> or C<.cshrc>.
243             These are created to help people that only want or need a single local lib and
244             would like to activate it at login. If you'd like to use these, simple add the
245             following tot he end of your C<.bashrc>
246              
247             source $TARGET/bin/localenv-bashrc
248              
249             Where $TARGET is the root of your local lib (the directory that contains your
250             C and C directories created when you ran the helper).
251              
252             Next time you log in, you can do C and should see that your local-lib
253             has automatically been activated.
254              
255             There will also be a C created for those of
256             you using csh. Currently this is not going to work with Windows shell users,
257             but should be easy to setup, collaborations very welcomed.
258              
259             =head1 OPTIONS
260              
261             This class supports the following options.
262              
263             =over 4
264              
265             =item which_perl
266              
267             This should be the path to the perl binary that the L is built
268             against. This defaults to the path of the perl binary under which we are
269             currently running. You should probably leave this one alone :)
270              
271             =item target
272              
273             This is the target directory for the L you want to build the helper
274             script against. By default it will attempt to detect the currently running
275             L and use that. If we can't detect a running L and
276             this option is undef, we die with a message.
277              
278             =item helper_name
279              
280             This is the name of the helper utility script. It defaults to 'localenv'.
281              
282             =item helper_permissions
283              
284             These are the permissions the the helper utility script is set to. By default
285             we set the equivilent of 'chmod 755 [HELPER SCRIPT]'
286              
287             =back
288              
289             =head1 HELPERS
290              
291             This distribution installs the following L helpers
292              
293             =head2 localenv
294              
295             This is a perl script that runs a single command in L aware context.
296             You can use the C option to set a different name.
297              
298             Typically I will use this to 'enable' a previously setup L with
299             commands like:
300              
301             ~/mylocallib/bin/localenv bash
302             ~/mylocallib/bin/localenv screen
303              
304             Or I can use it to run a single command wrapped in the L target
305             and exit cleanly:
306              
307             ~/mylocallib/bin/localenv perl app.pl
308             ~/mylocallib/bin/localenv plackup app.psgi
309              
310             =head2 localenv-relative
311              
312             NOTE: Experimental feature. Please prefer using L unless you
313             absolutely need this functionality.
314              
315             This perl script functions (or should function) identically to L as
316             documented. However, instead of having hardcoded full paths to your Perl
317             binary and L target directories, we instead try to use relative
318             pathing. For example, here is the helper script built on my server for the
319             standard L script:
320              
321             #!/Users/johnn/perl5/perlbrew/perls/perl-5.14.1/bin/perl
322              
323             use strict;
324             use warnings;
325              
326             use lib '/Users/johnn/locallib_5_14_1/lib/perl5';
327             use local::lib '/Users/johnn/locallib_5_14_1';
328              
329             unless ( caller ) {
330             if ( @ARGV ) {
331             exec @ARGV;
332             }
333             }
334              
335             And here is the example same version for the relative script:
336              
337             #!/usr/bin/env perl
338              
339             use strict;
340             use warnings;
341              
342             use FindBin;
343             use File::Spec;
344             use lib File::Spec->catdir($FindBin::Bin, '..', 'lib', 'perl5');
345             use local::lib File::Spec->catdir($FindBin::Bin, '..');
346              
347             unless ( caller ) {
348             if ( @ARGV ) {
349             exec @ARGV;
350             }
351             }
352              
353             The goal here is to be more friendly when you need to relocate your
354             installation of Perl and/or your L target directory. You might
355             wish to try this if you are copying a 'seed' Perl and L setup to
356             multiple developer home directories (as a way to speed up first time developer
357             setup, for example) or if your deployment system copies your application from
358             your build enviroment to a QA or Production that is not identical.
359              
360             Personally I prefer to build Perl and my application in each location that is
361             different, since I find that works very effectively. However I understand some
362             shops have existing build systems that deploy code by copying Perl dependencies
363             from box to box, and these boxes are not always identical in directory layout.
364             For example, there might be a build or integration point in development, with
365             a L target of C and you
366             wish to copy that directory recursively to your qa/production server, which
367             might be located at C.
368              
369             I'd like to accomodate this approach as best I can, however I can't be certain
370             that moving Perl and L around rather than performing a true install
371             is going to work consistently. Caveat emptor!
372              
373             Please also note that the following shell snippets are not relative tested.
374              
375             =head2 localenv-bashrc
376              
377             a snippet suitable for sourcing in your .bashrc, which will automatically
378             activate a local-lib at login. Name will follow from C.
379              
380             Here's an example of the line I might add to .bashrc (assumes you have setup
381             L in C<$HOME/mylocal>
382              
383             source $HOME/mylocal/localenv-bashrc
384              
385             Then next time you open a shell you should see that C<$PATH> and C
386             have been properly changed.
387              
388             =head2 localenv-cshrc
389              
390             a snippet suitable for sourcing in your .cshrc, which will automatically
391             activate a local-lib at login. Name will follow from C.
392              
393              
394             =head1 AUTHOR
395              
396             John Napiorkowski C< <> >
397              
398             =head1 COPYRIGHT & LICENSE
399              
400             Copyright 2011, John Napiorkowski
401              
402             This program is free software; you can redistribute it and/or modify it under
403             the same terms as Perl itself.
404              
405             =cut
406              
407