File Coverage

blib/lib/Portable.pm
Criterion Covered Total %
statement 30 92 32.6
branch 5 38 13.1
condition 2 29 6.9
subroutine 8 28 28.5
pod 0 19 0.0
total 45 206 21.8


line stmt bran cond sub pod time code
1             package Portable;
2            
3             =pod
4            
5             =head1 NAME
6            
7             Portable - Perl on a Stick
8            
9             =head1 SYNOPSIS
10            
11             Launch a script portably
12            
13             F:\anywhere\perl.exe -MPortable script.pl
14            
15             Have a script specifically request to run portably
16            
17             #!/usr/bin/perl
18             use Portable;
19            
20             =head1 DESCRIPTION
21            
22             "Portable" is a term used for applications that are installed onto a
23             portable storage device (most commonly a USB memory stick) rather than
24             onto a single host.
25            
26             This technique has become very popular for Windows applications, as it
27             allows a user to make use of their own software on typical publically
28             accessible computers at libraries, hotels and internet cafes.
29            
30             Converting a Windows application into portable form has a specific set
31             of challenges, as the application has no access to the Windows registry,
32             no access to "My Documents" type directories, and does not exist at a
33             reliable filesystem path (because the portable storage medium can be
34             mounted at an arbitrary volume or filesystem location).
35            
36             B provides a methodology and implementation to support
37             the creating of "Portable Perl" applications and distributions.
38            
39             While this will initially be focused on a Windows implementation,
40             wherever possible the module will be built to be platform-agnostic
41             in the hope that future versions can support other operating systems,
42             or work across multiple operating systems.
43            
44             This module is not ready for public use. For now, see the code for
45             more details on how it works...
46            
47             =head1 METHODS
48            
49             =cut
50            
51 4     4   2552 use 5.008;
  4         12  
  4         135  
52 4     4   20 use strict;
  4         5  
  4         124  
53 4     4   25 use warnings;
  4         8  
  4         124  
54 4     4   2076 use Portable::LoadYaml;
  4         9  
  4         174  
55 4     4   2126 use Portable::FileSpec;
  4         9  
  4         4984  
56            
57             our $VERSION = '1.22';
58            
59             # This variable is provided exclusively for the
60             # use of test scripts.
61             our $FAKE_PERL;
62            
63             # Globally-accessible flag to see if Portable is enabled.
64             # Defaults to undef, because if Portable.pm is not loaded
65             # AT ALL, $Portable::ENABLED returns undef anyways.
66             our $ENABLED = undef;
67            
68             # Param-checking
69             sub _STRING ($) {
70 0 0 0 0   0 (defined $_[0] and ! ref $_[0] and length($_[0])) ? $_[0] : undef;
71             }
72             sub _HASH ($) {
73 0 0 0 0   0 (ref $_[0] eq 'HASH' and scalar %{$_[0]}) ? $_[0] : undef;
74             }
75             sub _ARRAY ($) {
76 0 0 0 0   0 (ref $_[0] eq 'ARRAY' and @{$_[0]}) ? $_[0] : undef;
77             }
78            
79             # Package variables
80             my %applied;
81             my $cache;
82            
83            
84            
85            
86            
87             #####################################################################
88             # Pragma/Import Interface
89            
90             sub import {
91 1     1   8 my $class = shift;
92 1 50       26 $class->apply( @_ ? @_ : qw{ Config CPAN } );
93             }
94            
95             sub apply {
96             # default %applied;
97 1     1 0 2 my $class = shift;
98 1         3 my $self = $class->default;
99 0         0 my %apply = map { $_ => 1 } @_;
  0         0  
100 0 0 0     0 if ( $apply{Config} and ! $applied{Config} ) {
101 0         0 $self->config->apply($self);
102 0         0 $applied{Config} = 1;
103 0         0 $ENABLED = 1;
104             }
105 0 0 0     0 if ( $apply{CPAN} and ! $applied{CPAN} and $self->cpan ) {
      0        
106 0         0 $self->cpan->apply($self);
107 0         0 $applied{CPAN} = 1;
108 0         0 $ENABLED = 1;
109             }
110 0 0 0     0 if ( $apply{HomeDir} and ! $applied{HomeDir} and $self->homedir ) {
      0        
111 0         0 $self->homedir->apply($self);
112 0         0 $applied{HomeDir} = 1;
113 0         0 $ENABLED = 1;
114             }
115            
116             # We don't need to do anything for CPAN::Mini.
117             # It will load us instead (I think)
118            
119 0         0 return 1;
120             }
121            
122             sub applied {
123 0     0 0 0 $applied{$_[1]};
124             }
125            
126            
127            
128            
129            
130             #####################################################################
131             # Constructors
132            
133             sub new {
134 0     0 0 0 my $class = shift;
135 0         0 my $self = bless { @_ }, $class;
136            
137             # Param checking
138 0 0       0 unless ( exists $self->{dist_volume} ) {
139 0         0 die('Missing or invalid dist_volume param');
140             }
141 0 0       0 unless ( _STRING($self->dist_dirs) ) {
142 0         0 die('Missing or invalid dist_dirs param');
143             }
144 0 0       0 unless ( _STRING($self->dist_root) ) {
145 0         0 die('Missing or invalid dist_root param');
146             }
147 0 0       0 unless ( _HASH($self->{portable}) ) {
148 0         0 die('Missing or invalid portable param');
149             }
150            
151             # Compulsory support for Config.pm
152 0         0 require Portable::Config;
153 0         0 $self->{Config} = Portable::Config->new( $self );
154            
155             # Optional support for CPAN::Config
156 0 0       0 if ( $self->portable_cpan ) {
157 0         0 require Portable::CPAN;
158 0         0 $self->{CPAN} = Portable::CPAN->new( $self );
159             }
160            
161             # Optional support for File::HomeDir
162 0 0       0 if ( $self->portable_homedir ) {
163 0         0 require Portable::HomeDir;
164 0         0 $self->{HomeDir} = Portable::HomeDir->new( $self );
165             }
166            
167             # Optional support for CPAN::Mini
168 0 0       0 if ( $self->portable_minicpan ) {
169 0         0 require Portable::minicpan;
170 0         0 $self->{minicpan} = Portable::minicpan->new( $self );
171             }
172            
173 0         0 return $self;
174             }
175            
176             sub default {
177             # state $cache;
178 3 50   3 0 1380 return $cache if $cache;
179            
180             # Get the perl executable location
181 3 50 33     43 my $perlpath = ($ENV{HARNESS_ACTIVE} and $FAKE_PERL) ? $FAKE_PERL : $^X;
182            
183             # The path to Perl has a localized path.
184             # G:\\strawberry\\perl\\bin\\perl.exe
185             # Split it up, and search upwards to try and locate the
186             # portable.perl file in the distribution root.
187 3         12 my ($dist_volume, $d, $f) = Portable::FileSpec::splitpath($perlpath);
188 3         13 my @d = Portable::FileSpec::splitdir($d);
189 3 50 33     33 pop @d if @d > 0 && $d[-1] eq '';
190 24         59 my @tmp = grep {
191 24         73 -f Portable::FileSpec::catpath( $dist_volume, $_, 'portable.perl' )
192             }
193             map {
194 3         13 Portable::FileSpec::catdir(@d[0 .. $_])
195             } reverse ( 0 .. $#d );
196 3         14 my $dist_dirs = $tmp[0];
197 3 50       9 unless ( defined $dist_dirs ) {
198 3         445 die("Failed to find the portable.perl file");
199             }
200            
201             # Derive the main paths from the plain dirs
202 0           my $dist_root = Portable::FileSpec::catpath($dist_volume, $dist_dirs, '' );
203 0           my $conf = Portable::FileSpec::catpath($dist_volume, $dist_dirs, 'portable.perl' );
204            
205             # Load the YAML file
206 0           my $portable = Portable::LoadYaml::load_file( $conf );
207 0 0         unless ( _HASH($portable) ) {
208 0           die("Missing or invalid portable.perl file");
209             }
210            
211             # Hand off to the main constructor,
212             # cache the result and return it
213 0           $cache = __PACKAGE__->new(
214             dist_volume => $dist_volume,
215             dist_dirs => $dist_dirs,
216             dist_root => $dist_root,
217             conf => $conf,
218             perlpath => $perlpath,
219             portable => $portable,
220             );
221             }
222            
223            
224            
225            
226            
227             #####################################################################
228             # Configuration Accessors
229            
230             sub dist_volume {
231 0     0 0   $_[0]->{dist_volume};
232             }
233            
234             sub dist_dirs {
235 0     0 0   $_[0]->{dist_dirs};
236             }
237            
238             sub dist_root {
239 0     0 0   $_[0]->{dist_root};
240             }
241            
242             sub conf {
243 0     0 0   $_[0]->{conf};
244             }
245            
246             sub perlpath {
247 0     0 0   $_[0]->{perlpath};
248             }
249            
250             sub portable_cpan {
251 0     0 0   $_[0]->{portable}->{CPAN};
252             }
253            
254             sub portable_config {
255 0     0 0   $_[0]->{portable}->{Config};
256             }
257            
258             sub portable_homedir {
259 0     0 0   $_[0]->{portable}->{HomeDir};
260             }
261            
262             sub portable_minicpan {
263 0     0 0   $_[0]->{portable}->{minicpan};
264             }
265            
266             sub portable_env {
267 0     0 0   $_[0]->{portable}->{Env};
268             }
269            
270             sub config {
271 0     0 0   $_[0]->{Config};
272             }
273            
274             sub cpan {
275 0     0 0   $_[0]->{CPAN};
276             }
277            
278             sub homedir {
279 0     0 0   $_[0]->{HomeDir};
280             }
281            
282             sub minicpan {
283 0     0 0   $_[0]->{minicpan};
284             }
285            
286             sub env {
287 0     0 0   $_[0]->{Env};
288             }
289            
290             1;
291            
292             =pod
293            
294             =head1 SUPPORT
295            
296             Bugs should be reported via the CPAN bug tracker.
297            
298             L
299            
300             For other issues, or commercial support, contact the author.
301            
302             =head1 AUTHOR
303            
304             Adam Kennedy Eadamk@cpan.orgE
305            
306             =head1 SEE ALSO
307            
308             L
309            
310             =head1 COPYRIGHT
311            
312             Copyright 2008 - 2011 Adam Kennedy.
313            
314             This program is free software; you can redistribute
315             it and/or modify it under the same terms as Perl itself.
316            
317             The full text of the license can be found in the
318             LICENSE file included with this module.
319            
320             =cut