File Coverage

blib/lib/App/Packager.pm
Criterion Covered Total %
statement 27 81 33.3
branch 1 42 2.3
condition 0 6 0.0
subroutine 7 17 41.1
pod 0 6 0.0
total 35 152 23.0


line stmt bran cond sub pod time code
1             #! perl
2              
3             package App::Packager;
4              
5 1     1   48777 use strict;
  1         1  
  1         22  
6 1     1   4 use warnings;
  1         1  
  1         20  
7 1     1   4 use Carp;
  1         1  
  1         54  
8              
9 1     1   350 use parent qw(Exporter);
  1         270  
  1         4  
10             our @EXPORT_OK = qw( GetUserFile GetResource SetResourceName );
11              
12             # Implementation agnostic packager support.
13              
14             our $VERSION = "1.430";
15             our $PACKAGED = 0;
16             our $RESNAME = "";
17              
18             ### Establish access methods depending on the packer.
19              
20             # Check for PAR::Packer.
21             if ( $ENV{PAR_0} ) {
22             require PAR;
23             $VERSION = $PAR::VERSION;
24             $PACKAGED = 1;
25             *IsPackaged = sub { 1 };
26             *GetScriptCommand = sub { $ENV{PAR_PROGNAME} };
27             *GetAppRoot = sub { $ENV{PAR_TEMP} };
28             *GetResourcePath = sub { $ENV{PAR_TEMP} . "/inc/res" };
29             *GetResource = sub { $ENV{PAR_TEMP} . "/inc/res/" . $_[0] };
30             *GetUserFile = sub { $ENV{PAR_TEMP} . "/inc/user/" . $_[0] };
31             *Packager = sub { "PAR" };
32             *Version = sub { "$PAR::VERSION" };
33             }
34              
35             # Cava::Packager.
36             elsif ( $Cava::Packager::PACKAGED ) {
37             $VERSION = $Cava::Packager::VERSION;
38             $PACKAGED = 1;
39             *Packager = sub { "Cava Packager" };
40             *Version = sub { "$VERSION" };
41             *IsPackaged = sub { 1 };
42             }
43              
44             # Unpackaged, use file system.
45             else {
46 0     0   0 *Packager = sub { "App Packager" };
47 0     0   0 *Version = sub { "$VERSION" };
48 0     0   0 *IsPackaged = sub { return };
49             *GetResourcePath = \&U_GetResourcePath;
50             *GetResource = \&U_GetResource;
51             *GetUserFile = \&U_GetUserFile;
52             }
53              
54             #### Optional packaged, mandatory if unpackaged.
55              
56             sub SetResourceName {
57 0     0 0 0 $RESNAME = shift;
58 0         0 $RESNAME =~ s;::;/;g;
59 0         0 $RESNAME =~ s;/+$;;;
60             }
61              
62             sub GetResourceName {
63 0     0 0 0 $RESNAME;
64             }
65              
66             #### Resource routines for the unpacked case.
67              
68             sub U_GetUserFile {
69 0 0   0 0 0 return if $RESNAME eq "";
70 0         0 my $file = shift;
71 0         0 foreach ( @INC ) {
72 0 0       0 return "$_/$RESNAME/user/$file" if -e "$_/$RESNAME/user/$file";
73             }
74 0         0 undef;
75             }
76              
77             sub U_GetResource {
78 0 0   0 0 0 return if $RESNAME eq "";
79 0         0 my $file = shift;
80 0         0 foreach ( @INC ) {
81 0 0       0 return "$_/$RESNAME/res/$file" if -e "$_/$RESNAME/res/$file";
82             }
83 0         0 foreach ( @INC ) {
84 0 0       0 return "$_/$RESNAME/$file" if -e "$_/$RESNAME/$file";
85             }
86 0         0 undef;
87             }
88              
89             sub U_GetResourcePath {
90 0 0   0 0 0 return if $RESNAME eq "";
91 0         0 foreach ( @INC ) {
92 0 0       0 return "$_/$RESNAME/res" if -d "$_/$RESNAME/res";
93             }
94 0         0 undef;
95             }
96              
97             #### Usually, this is all what is needed.
98              
99             sub getresource {
100 0     0 0 0 my ( $file ) = @_;
101              
102 0         0 my $found = App::Packager::GetUserFile($file);
103 0 0 0     0 return $found if defined($found) && -e $found;
104 0         0 $found = App::Packager::GetResource($file);
105 0 0 0     0 return $found if defined($found) && -e $found;
106 0 0       0 return unless $App::Packager::PACKAGED;
107 0 0       0 return if $RESNAME eq "";
108              
109 0         0 foreach ( @INC ) {
110 0 0       0 return "$_/$RESNAME/user/$file" if -e "$_/$RESNAME/user/$file";
111 0 0       0 return "$_/$RESNAME/res/$file" if -e "$_/$RESNAME/res/$file";
112 0 0       0 return "$_/$RESNAME/$file" if -e "$_/$RESNAME/$file";
113             }
114              
115 0         0 return;
116             }
117              
118             #### Import handling.
119             #
120             # Bij default, the getresource routine is exported, but its name
121             # can be changed by using ":rsc" => "alternative name".
122              
123             sub import {
124 1     1   8 my $pkg = shift;
125              
126 1         1 my @syms = (); # symbols to import
127 1         2 my $rsc = "getresource";
128              
129 1         3 while ( @_ ) {
130 0         0 $_ = shift;
131 0 0       0 if ( $_ eq ':name' ) {
132 0 0       0 SetResourceName(shift) if @_ > 0;
133 0         0 next;
134             }
135 0 0       0 if ( $_ eq ':rsc' ) {
136 0 0       0 $rsc = shift if @_ > 0;
137 0         0 next;
138             }
139 0         0 push( @syms, $_ );
140             }
141              
142 1 50       2 if ( $rsc ) {
143 1         3 my $pkg = (caller)[0];
144 1     1   775 no strict 'refs';
  1         1  
  1         149  
145 1         1 *{ $pkg . "::" . $rsc } = \&getresource;
  1         4  
146             }
147              
148             # Dispatch to super.
149 1         82 $pkg->export_to_level( 1, $pkg, @syms );
150             }
151              
152             # Unknown routines are dispatched to Cava::Packager, which provides
153             # packaged and non-packaged functions.
154              
155             our $AUTOLOAD;
156              
157             sub AUTOLOAD {
158 0     0     my $sub = $AUTOLOAD;
159 0           $sub =~ s/^App\:\:Packager\:\://;
160              
161 0 0         eval { require Cava::Packager } unless $Cava::Packager::PACKAGED;
  0            
162 0           my $can = Cava::Packager->can($sub);
163 0 0         unless ( $can ) {
164 0           require Carp;
165 0           Carp::croak("Undefined subroutine \&$AUTOLOAD called");
166             }
167              
168 1     1   6 no strict 'refs';
  1         2  
  1         76  
169 0           *{'App::Packager::'.$sub} = $can;
  0            
170 0           goto &$AUTOLOAD;
171             }
172              
173             1;
174              
175             =head1 NAME
176              
177             App::Packager - Abstraction for Packagers
178              
179             =head1 SYNOPSIS
180              
181             App::Packager provides an abstract interface to a number of common
182             packagers, trying to catch as much common behaviour as possible.
183              
184             The main purpose is to have uniform access to application specific
185             resources.
186              
187             Supported packagers are PAR::Packer, Cava::Packager and unpackaged. In
188             the latter case, resources are looked up in @PATH, and the name of the
189             application package must be passed to the first C of
190             App::Packager.
191              
192             For example:
193              
194             use App::Packager qw(:name My::App);
195             print "My packager is: ", App::Packager::Packager(), "\n";
196             print getresource("README.txt");
197              
198             =head1 EXPORT
199              
200             By default, function C is exported. It can be exported
201             under a different name by providing an alternative name as follows:
202              
203             use App::Packager( ':rsc' => '...alternative name...' );
204              
205             =head1 FUNCTIONS
206              
207             =head2 App::Packager::Packager
208              
209             Returns the name of the actual packager, or C if unpackaged.
210              
211             =head2 App::Packager::Version
212              
213             Returns the version of the packager.
214              
215             =head2 App::Packager::IsPackaged
216              
217             Returns true if the application was packaged.
218              
219             Note that it is usually easier, and safer, to use
220             $App::Packager::PACKAGED for testing since that will work even if
221             App::Packager is not available.
222              
223             =head1 App::Packager::GetResourcePath
224              
225             Returns the path name of the application resources directory.
226              
227             =head1 App::Packager::GetResource($rsc)
228              
229             Returns the file name of the application resource.
230              
231             =head1 App::Packager::GetUserFile($rsc)
232              
233             Returns the file name of the user specific resource.
234              
235             =cut
236              
237             =head1 AUTHOR
238              
239             Johan Vromans, C<< >>
240              
241             =head1 SUPPORT
242              
243             Development of this module takes place on GitHub:
244             L.
245              
246             You can find documentation for this module with the perldoc command.
247              
248             perldoc App::Packager
249              
250             Please report any bugs or feature requests using the issue tracker on
251             GitHub.
252              
253             =back
254              
255             =head1 ACKNOWLEDGEMENTS
256              
257             This module was inspired by Mark Dootson's Cava packager.
258              
259             =head1 COPYRIGHT & LICENSE
260              
261             Copyright 2017,2018 Johan Vromans, all rights reserved.
262              
263             This program is free software; you can redistribute it and/or modify it
264             under the same terms as Perl itself.
265              
266             =cut
267              
268             1;