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