File Coverage

bin/fetchware
Criterion Covered Total %
statement 361 463 77.9
branch 80 138 57.9
condition 6 15 40.0
subroutine 59 65 90.7
pod n/a
total 506 681 74.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             # I know lowercase names are reserved for pragma's, but other programs do this
3             # such as perlbrew and dzil. It makes loading this program for testing very easy
4             # with Cimport();>, and it
5             # bypasses a limitation in dzil regarding creating the POD properly.
6              
7             package fetchware;
8             our $VERSION = '1.015'; # VERSION: generated by DZP::OurPkgVersion
9             # ABSTRACT: Fetchware is a package manager for source code distributions.
10 44     44   67128 use strict;
  44         70  
  44         3077  
11 34     34   114 use warnings;
  34         33  
  34         1027  
12              
13             # Enable Perl 6 knockoffs, and use 5.10.1, because smartmatching and other
14             # things in 5.10 were changed in 5.10.1+.
15 33     33   442 use 5.010001;
  33         67  
16              
17             # Use Getopt::Long for options parsing beyond fetchware's simple commands such
18             # as install, new, uninstall, help, and so on.
19 33     33   20355 use Getopt::Long qw(:config bundling pass_through);
  33         240061  
  33         132  
20             ###BUGALERT### This breaks App::Fetchware's encapsulation, and screws up its API
21             #fix this bug by extracting the fetchwarefile without relying on start() having
22             #already created the temp directory!!!!!!
23 33     33   41710 use App::Fetchware qw(parse_directory_listing);
  33         95  
  33         2922  
24 33     33   230 use App::Fetchware::Config qw(config __clear_CONFIG config_replace);
  33         35  
  33         1411  
25 33     33   110 use App::Fetchware::Util qw(:UTIL);
  33         38  
  33         4674  
26 33     33   113 use Test::Fetchware 'create_test_fetchwarefile';
  33         32  
  33         1206  
27 33     33   13704 use App::Fetchware::Fetchwarefile;
  33         61  
  33         762  
28 33     33   130 use Archive::Tar;
  33         53  
  33         1480  
29 33     33   109 use File::Copy qw(mv cp);
  33         55  
  33         1348  
30 33         2032 use File::Spec::Functions qw(curdir catdir catfile catpath tmpdir splitpath
31 33     33   109 splitdir rel2abs abs2rel updir file_name_is_absolute);
  33         54  
32 33     33   107 use Cwd 'cwd';
  33         50  
  33         1008  
33 33     33   107 use File::Path qw(make_path remove_tree);
  33         32  
  33         1090  
34 33     33   109 use Term::UI;
  33         51  
  33         531  
35 33     33   107 use Term::ReadLine;
  33         34  
  33         742  
36 33     33   101 use Perl::OSType 'is_os_type';
  33         34  
  33         995  
37 33     33   13763 use File::HomeDir;
  33         118063  
  33         1433  
38 33     33   161 use File::Find 'find';
  33         34  
  33         1410  
39 33     33   140 use File::Temp 'tempfile';
  33         34  
  33         1094  
40 33     33   121 use Fcntl qw(SEEK_SET);
  33         35  
  33         1008  
41 33     33   120 use Path::Class;
  33         39  
  33         1215  
42 33     33   99 use Text::Wrap 'wrap';
  33         52  
  33         865  
43 33     33   101 use Data::Dumper;
  33         74  
  33         981  
44 33     33   115 use Fcntl ':flock';
  33         54  
  33         2992  
45 33     33   134 use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
  33         33  
  33         2538  
46 33     33   108 use Sub::Mage;
  33         56  
  33         250  
47 33     33   4784 use URI::Split qw(uri_split uri_join);
  33         35  
  33         1248  
48 33     33   121 use Scalar::Util 'blessed';
  33         56  
  33         1222  
49 33     33   105 use Module::Load 'load';
  33         53  
  33         196  
50              
51             # Setup exports, which are only meant to ease testing.
52 33     33   1487 use Exporter 'import';
  33         72  
  33         102612  
53             our %EXPORT_TAGS = (
54             TESTING => [qw(
55             parse_fetchwarefile
56             create_fetchware_package
57             fetchware_database_path
58             determine_fetchware_package_path
59             extract_fetchwarefile
60             copy_fpkg_to_fpkg_database
61             cmd_install
62             cmd_uninstall
63             cmd_look
64             cmd_list
65             cmd_upgrade
66             cmd_upgrade_all
67             cmd_new
68             cmd_clean
69             run
70             )]
71             );
72             our @EXPORT_OK = @{$EXPORT_TAGS{TESTING}};
73              
74             our $verbose = 0;
75             our $quiet = 0;
76             our $dry_run = 0;
77              
78             # Be a modulino, so I can "use fetchware" in my test suite, so I can test
79             # bin/fetchware normally like any other perl module.
80             ###BUGALERT## Add a test suite for run(), and also one that directly calls
81             #bin/fetchware to test its command line options.
82             run() unless caller();
83              
84             sub run {
85             # Set up a %SIG handler for CTRL-C or CTRL-Z on Windows.
86             # And a %SIG handler for QUIT, which is CTRL-\
87             #
88             # Define a $parent_pid, so I can compare it to $$ (the current pid) to
89             # see if I'm the child or the parent inside the sig handler to act
90             # accordingly.
91 17     17   923 my $parent_pid = $$;
92             #
93             # Be sure to prepend the first message that's printed with a newline to
94             # ensure that it's printed on a brand new fresh line.
95             @SIG{qw(INT TERM QUIT)} = sub {
96 0     0   0 my $sig = shift;
97             # Avoid a silly race condition where both the parent and the child both
98             # try to run this code at the same time resulting in the one closing the
99             # file and deleting the tempdir() before the other one resulting in
100             # strange undefined warnings.
101             #
102 0 0       0 if ($parent_pid == $$) {
103 0         0 msg <
104             \nSignal [$sig] received. Cleaning up Fetchware.
105             EOM
106 0         0 vmsg <
107             Any temporary files that fetchware may have created will be deleted by
108             File::Temp's END block.
109             EOM
110              
111 0         0 cleanup_tempdir();
112             }
113              
114             # Exit failure, because fetchware failed to properly install your
115             # software while it was running, because the signal it received forced
116             # it to exit prematurely making it questionable if fetchware succeeded
117             # in properly and completely completing the actions you specified on the
118             # command line and/or in a Fetchwarefile.
119 0         0 exit 1;
120 17         1670 };
121              
122 17         562 vmsg 'Parsing command line options using Getopt::Long';
123              
124             GetOptions(
125             # $VERSION is managed by dzil; therefore, I use eval to access it at
126             # run time instead of compile time, so that I can test fetchware without
127             # running dzil test.
128 2     2   2048 'version|V' => sub { eval 'say "Fetchware version $fetchware::VERSION"; '; exit 0},
  2         573  
129 17         893 'help|h|?' => \&cmd_help,
130             'verbose|v' => \$verbose,
131             'quiet|q' => \$quiet,
132             # Expose File::Temp's KEEP_ALL flag, and an easy feature to implement
133             # that lets users easily ensure the tempdir stays around when needed.
134             'keep-temp|K' => \$File::Temp::KEEP_ALL,
135             ###BUGALERT### dry-run functionality is *not* implemented!!!
136             #'dry-run|d' => \$dry_run,
137             );
138              
139              
140             # Getopt::Long is *only* used to determine dash and double dash style options
141             # such as -v, --verbose, --help, -h, -?, etc....
142             #
143             # Below the first argument to fetchware is used to determine what fetchware
144             # does. If nothing is specified then help is printed.
145             ###BUGALERT### Add a loop around @ARGV to support multiple Fetchwarefiles
146             #or fetchware packages ending in .fpkg.
147 12         8337 eval { # Trap any fatal errors.
148 12         129 vmsg 'Entering main eval{} block to trap errors.';
149             ###BUGALERT### Should trapped exceptions with this eval cause fetchware
150             #to cd to $original_cwd and then exit, so that the File::Temp's END
151             #block can delete fetchware's source dir???
152             # Or fetchware could print the path of this source dir and close, and
153             # tell the user that they can clean it up with fetchware clean??
154             # Also, add cmdline options to control what to do when this happens???
155 12         117 vmsg 'Determining which command to run based on command line options.';
156 12         19 my $command;
157 12 100       164 @ARGV ? ($command = shift @ARGV) : ($command = '');
158 12 100       282 if ($command eq 'install') {
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
159 2         20 cmd_install(@ARGV);
160             } elsif ($command eq 'uninstall') {
161 1         20 cmd_uninstall(@ARGV);
162             } elsif ($command eq 'new') {
163 0         0 cmd_new(@ARGV);
164             } elsif ($command eq 'upgrade') {
165 2         37 cmd_upgrade(@ARGV);
166             } elsif ($command eq 'upgrade-all') {
167 1         11 cmd_upgrade_all(@ARGV);
168             } elsif ($command eq 'list') {
169 1         15 cmd_list(@ARGV);
170             } elsif ($command eq 'look') {
171 1         18 cmd_look(@ARGV);
172             } elsif ($command eq 'clean') {
173 1         15 cmd_clean(@ARGV);
174             } elsif ($command eq 'help') {
175 1         11 cmd_help(@ARGV);
176             } else {
177 2         18 cmd_help(@ARGV);
178             }
179             # Exit success, because if any of the main subroutines run into any
180             # problems they die() exceptions, which get caught in eval above, and
181             # warn()ed below, and fetchware exits 1 for failure.
182 9         59 vmsg 'Fetchware ran successfully! Exiting with status of 0 for success!';
183 9         1706 exit 0;
184             };
185             # If a fatal error was thrown print it to STDERR and exit indicating failure.
186 0 0       0 if ($@) {
187             # Set File::Temp's $KEEP_ALL so user can troubleshoot what happend
188             # without having to bother to use --keep-all.
189 0         0 $File::Temp::KEEP_ALL = 1;
190 0         0 msg <
191             Fetchware threw an exception! Exiting with an exit status of 1 for failure.
192 0         0 Fetchware failed inside directory [@{[cwd()]}].
193             EOM
194 0         0 warn $@;
195 0         0 exit 1;
196             }
197             }
198              
199              
200              
201              
202              
203             ###BUGALERT### cmd_install() does *not* actually do this. Consider implementing
204             #it.
205             #If no filename was
206             #provided or the filename doesn't exist then, cmd_install() calls new() to create
207             #and install a new fetchware package.
208              
209              
210             sub cmd_install {
211             # These variables must be shared back to the parent from the child using
212             # pipe_{write,read}_newline().
213 84     84   3822 my $P_build_path;
214             ###BUGALERT### After verifying basic functionality of cmd_install wrap
215             #subroutine contents in a for my $filename (pop @ARGV) loop to try to
216             #install all given arguments that arn't command line options as parsed by
217             #GetOpt::Long.
218             ### Add this loop in run(), so there is just one loop to test.
219 84         192 my $filename = shift;
220            
221 84         98 my $output;
222 84 100 100     1847 if (defined($filename) and -e $filename) {
223              
224 82         553 msg "Starting fetchware install to install [$filename]";
225              
226             # If a fpkg extract out the Fetchwarefile into a scalar, and if not a
227             # fetchware package to go ahead and open for reading only the Fetchware
228             # right now while we're perhaps still root, so we can be sure we can
229             # still access it.
230 82         162 my $fetchwarefile;
231 82 50       851 if ($filename =~ /\.fpkg$/) {
232 82         450 $fetchwarefile = extract_fetchwarefile($filename);
233 82         590 vmsg <
234             Extracting out Fetchwarefile from [$filename] to [$$fetchwarefile]
235             EOM
236             } else {
237 0         0 my $fh = safe_open($filename, <
238             fetchware: Fetchware failed to open the filename you specified to fetchware
239             install [$filename]. The OS error was [$!].
240             EOD
241 0         0 vmsg "Opened file [$filename] for slurping.";
242             # Add a \ to turn the slurped scalar into a scalar ref for calling
243             # parse_fetchwarefile() properly.
244 0         0 $fetchwarefile = \do {local $/; <$fh>};
  0         0  
  0         0  
245 0         0 vmsg "Slurped [$filename] into fetchware: [$$fetchwarefile]";
246             }
247              
248             # Must parse the Fetchwarefile in the parent, so that the parent has access
249             # to the imported subroutines and modified fetchware configuration (%CONFIG)
250             # just as the child does.
251 82         621 parse_fetchwarefile($fetchwarefile);
252 82         448 vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
253              
254              
255             # start() runs as root before the fork, because it uses
256             # App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
257             # subroutine uses a variable to store an open filehandle to a
258             # "fetchware.sem" semaphore file. This filehandle must stay open and locked
259             # using flock, because otherwise a "fetchware clean" run could delete the
260             # temporary directory out from under fetchware. Therefore, the parent must
261             # open this semaphore, because the child if it runs start() will close this
262             # file handle when it exits causing cleanup_tempdir() to freak out when
263             # end() is called.
264 82         646 my $temp_dir = start();
265              
266             # Drop privs, so only install() and end() are called with root perms
267             $output = drop_privs(
268             sub {
269 0     0   0 my $write_pipe = shift;
270              
271             # Run the App::Fetchware API subroutines to do everything to install
272             # the program, but be mindful of drop_privs() requiring this coderef
273             # to use write_dropprivs_pipe() to communicate needed changes back to
274             # the parent process, for example, $P_build_path--the parent needs to
275             # chdir() to that directory before it tries to execute install().
276              
277             ###BUGALERT### install installs no matter if the program is already
278             #installed!!! Change this to parse out the package from the
279             #download_urlif possible, compare with the one in the fetchware
280             #package database, and call exit right here if the current version
281             #is already installed unless of course --force is used!!!
282 0         0 my $download_url = lookup();
283              
284 0         0 my $package_path = download($temp_dir, $download_url);
285              
286             ###BUGALERT### Add support for caching the key files gpg creates to
287             #the fetchwarefile, and for actually using them later on inside the
288             #fpkg.
289 0         0 verify($download_url, $package_path);
290              
291 0         0 $P_build_path = unarchive($package_path);
292              
293 0         0 build($P_build_path);
294              
295             # Tell the parent, root, process the values of the variables the
296             # child calculated in this coderef, and write them across this pipe
297             # back to the parent
298 0         0 write_dropprivs_pipe($write_pipe, $P_build_path);
299 82         1543 }, config('user')
300             ); # End drop_privs().
301              
302             # Read from the pipe the child, the drop_privs()ed process, writes to to
303             # read the necessary values that correspond to the variables that the
304             # child must communicate back to the parent, so the parent can continue
305             # processing as though no fork()ing or priv dropping took place.
306 82         1599 ($P_build_path)
307             = read_dropprivs_pipe($output);
308              
309 82         198 my $installed_fetchware_package_path;
310 82 50       857 if (not config('no_install')) {
311 82         767 install($P_build_path);
312              
313 82         172 vmsg "Creating Fetchware package from [@{[cwd()]}].";
  82         175107  
314 82         162086 my $fetchware_package_path
315             =
316             create_fetchware_package($fetchwarefile, cwd());
317 82         748 vmsg "Created fetchware package at [$fetchware_package_path].";
318              
319 82         370 vmsg 'Installing created fetchware package to fetchware database.';
320 82         554 $installed_fetchware_package_path
321             = copy_fpkg_to_fpkg_database($fetchware_package_path);
322 82         417 vmsg <
323             Installed created fetchware package to [$installed_fetchware_package_path]
324             EOM
325             }
326              
327 82         755 end();
328              
329             # Return the path of the created and installed fetchware package.
330 82         750 return $installed_fetchware_package_path;
331             } else {
332             ###BUGALERT### Replace with warn for proposed for loop above to work???
333 2         11 die <
334             fetchware: You called fetchware install incorrectly. You must also specify
335             either a Fetchwarefile or a fetchware package that ends with [.fpkg].
336             EOD
337             }
338             }
339              
340              
341              
342              
343             sub cmd_uninstall {
344              
345 50     50   386894 my $uninstall_package_path = shift;
346              
347 50         380 msg "Uninstalling specified package [$uninstall_package_path]";
348              
349 50         302 my $fetchware_package_path
350             = determine_fetchware_package_path($uninstall_package_path);
351 50         301 vmsg <
352             Determined the path of this package in the fetchware database to be
353             [$fetchware_package_path].
354             EOM
355              
356             # Extract out the $fetchwarefile from the $fetchware_package_path.
357 50         114 my $fetchwarefile;
358 50 50       462 if ($fetchware_package_path =~ /\.fpkg$/) {
359 50         132728 $fetchwarefile
360             =
361             extract_fetchwarefile($fetchware_package_path, cwd());
362 49         418 vmsg <
363             Extracting out Fetchwarefile from [$fetchware_package_path] to [$$fetchwarefile]
364             EOM
365             } else {
366 0         0 die <
367             fetchware: The option you provided to uninstall is not a currently installed
368             fetchware package. Please rerun uninstall after determining the proper name for
369             the already installed fetchware package. To see a list of already installed
370             fetchware packages please try fetchware's list command: fetchware list
371             EOD
372             }
373              
374             # Must parse the Fetchwarefile in the parent, so that the parent has access
375             # to the imported subroutines and modified fetchware configuration (%CONFIG)
376             # just as the child does.
377 49         408 parse_fetchwarefile($fetchwarefile);
378 49         217 vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
379              
380             # start() runs as root before the fork, because it uses
381             # App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
382             # subroutine uses a variable to store an open filehandle to a
383             # "fetchware.sem" semaphore file. This filehandle must stay open and locked
384             # using flock, because otherwise a "fetchware clean" run could delete the
385             # temporary directory out from under fetchware. Therefore, the parent must
386             # open this semaphore, because the child if it runs start() will close this
387             # file handle when it exits causing cleanup_tempdir() to freak out when
388             # end() is called.
389 49         366 my $temp_dir = start();
390              
391             # "Download" the package using File::Copy's cp().
392 49         154 my $package_path;
393 49 50       479 if (cp($fetchware_package_path, $temp_dir)) {
394             # Determine the output file that cp() used.
395             ###BUGALERT### Open the file for cp(), and provide cp() with a
396             #filehandle to write the data to to ensure the filename is exactly
397             #what it needs to be.
398 49         21062 $package_path = catfile($temp_dir,
399             file($fetchware_package_path)->basename());
400             } else {
401 0         0 die <
402             fetchware: Fetchware failed to copy the file [$fetchware_package_path] to the
403             destination directory [$temp_dir]. OS error [$!].
404             EOD
405             }
406              
407              
408 49         7273 vmsg "Copied installed package to temporary directory at [$package_path]";
409              
410 49         487 my $build_path = unarchive($package_path);
411              
412 49         402 uninstall($build_path);
413              
414 49         305 end();
415              
416 49         304 vmsg 'Uninstalling fetchware package from fetchware database.';
417 49         451 uninstall_fetchware_package_from_database($fetchware_package_path);
418              
419 49         453 msg "Uninstalled fetchware package [$uninstall_package_path].";
420             # Return the name of the uninstalled package's full path fetchware's
421             # database.
422 49         975 return $fetchware_package_path;
423             }
424              
425              
426              
427             ###BUGALERT### Move cmd_new() before install()?????
428             ###BUGALERT### Print out fetchware's assumptions it makes about what FTP & hTTP
429             #lookup_url's look like, versionstring's assumptions, timestamp's assumptions,
430             #verify's assumptions, and so on. If not here in new() at least do it in the
431             #POD documentation.
432             ###BUGALERT### Support ~/.Fetchwarefile, or whatever File::HomeDir wants it to
433             #be. Test if ~/.Fetchwarefile exists, if it does do nothing, but if it does not
434             #exist then prompt the user to fill one out!!!
435              
436             ############BUGALERT########################BUGALERT##################
437             ############BUGALERT########################BUGALERT##################
438             ###BUGALERT### Modify analyze_lookup_listing() to print the directory listing
439             #for the user to peruse, and have the user choose what program they want to
440             #install from the listing. Then use that as the basis for the filter option.
441             #httpd-2.4.1.tar.bz2 would simply be m/(\w+?)[.-_\d]+?/ And $1 is the filter
442             #option. If the match fails to the existing manual crap.
443             ############BUGALERT########################BUGALERT##################
444             ############BUGALERT########################BUGALERT##################
445              
446             ###BUGALERT### Add a command line option to fetchware new that allows users to
447             #only edit a blank file (Have helpful comments about what options are must
448             #haves), and then have fetchware ask the user if they would like to then install
449             #that new Fetchwarefile.
450             ###BUGALERT### Rename lookup_url to main_mirror or master_mirror or author_mirror
451             #or something to better implicitly explain what it is.
452             ###BUGALERT### Add the check to see if there is a MIRRORS file or some similar
453             #regex, and if so parse it, and auto add it to the list of mirrors? Is this
454             #really feasible?
455              
456              
457             sub cmd_new {
458              
459             # These are the variables that the child must share back with the parent.
460 0     0   0 my $program_name = shift; # The child might change or define it again.
461              
462 0         0 my $term = Term::ReadLine->new('Fetchware new');
463              
464             # Must ask user what App::Fetchware extension they are going to create a
465             # Fetchwarefile for, so I can load that extension's new() and new_install()
466             # API subroutines, because *no* API subroutines are available until
467             # parse_fetchwarefile() is called in cmd_install(), and I can't call
468             # parse_fetchwarefile() before the user has answered the questons to
469             # actually create a Fetchwarefile.
470 0         0 my $fetchware_extension = $term->get_reply(
471             print_me => <
472             Unless you're using a Fetchware extension, press enter to continue along in the
473             creation of your new Fetchwarefile. If you are using a Fetchware extension,
474             please enter its name without the 'App::FetchwareX::' prefix.
475             EOP
476             prompt => q{Unless you're using a Fetchware extension press enter to use default?},
477             default => 'App::Fetchware',
478             );
479              
480             ###Security Note### Whatever string the user supplies will be given
481             #to Module::Load's load() subroutine, and then forwarded on to
482             #Perl's require() function, which parses and executes it as far as
483             #loading it goes, and then whatever new() and new_install()
484             #subroutines will be imported in the current package, and later one
485             #executed below new() with dropped privs, and new_install() as root
486             #if fun as root. You may consider this a security hole as it is
487             #never a good idea to execute user specified code, but considering
488             #later on cmd_new() via new() will ask the user if they want to edit
489             #the Fetchwarefile, where they can put whatever Perl code in it they
490             #want to, and then ask_to_install_now_to_test_fetchwarefile() will
491             #actually then run that Fetchwarefile, so that is also a security
492             #hole. However none of this really is a security hole, because the
493             #user could create a Perl program that does whatever bad stuff that
494             #they could use this to mess with Fetchware for.
495             ###Do basic security checking anyway.
496 0 0       0 die <
497             fetchware: The Fetchware extension you provided has characters that are not
498             allowed in fetchware extensions such as [../ , / , .pl , or .pm]. Please remove
499             these characters, and try again.
500             EOD
501 0 0       0 if (grep { $fetchware_extension eq $_ }
  0         0  
502             qw(App::Fetchware Fetchware fetchware default Default)
503             ) {
504 0         0 load 'App::Fetchware', qw(new new_install);
505             } else {
506             # Prepend the App::FetchwareX:: prefix for all fetchware
507             # extensions.
508 0         0 $fetchware_extension = "App::FetchwareX::$fetchware_extension";
509              
510 0         0 load $fetchware_extension, qw(new new_install);
511             }
512              
513            
514              
515             # Drop privs, so only install() is called with root permissions
516             my $output = drop_privs( sub {
517 0     0   0 my $write_pipe = shift;
518              
519              
520 0         0 my @pipe_args = new($term, $program_name);
521              
522             # Tell the parent, root, process the values of the variables the
523             # child calculated in this coderef, and write them across this pipe
524             # back to the parent
525 0         0 write_dropprivs_pipe($write_pipe, @pipe_args);
526 0         0 }, config('user'),
527             # cmd_new() does not want or need the directory that drop_privs() creates
528             # for the child so that the child can write files inside the parent's
529             # temporary directory that was created with start().
530             SkipTempDirCreation => 1
531             ); # End drop_privs() back to root now!
532              
533              
534             # Read from the pipe the child, the drop_privs()ed process, writes to to
535             # read the necessary values that correspond to the variables that the
536             # child must communicate back to the parent, so the parent can continue
537             # processing as though no fork()ing or priv dropping took place.
538 0         0 my (@pipe_args) = read_dropprivs_pipe($output);
539              
540             # Use our own term in the parent process. Writing the Term::ReadLine object
541             # across the pipe does not work, so just make your own in the parent
542             # process.
543 0         0 $term = Term::ReadLine->new('Fetchware new');
544              
545             # Call App::Fetchware's or an App::Fetchware extension's new_install() to
546             # install the previously generated Fetchwarefile, or whatever the
547             # extension's new_install() does in addition to or instead of.
548 0         0 return new_install($term, @pipe_args);
549             }
550              
551              
552              
553              
554              
555              
556             ###BUGALERT### Add a config sub for a command to run after upgrade.
557             #C that will allow you to restart apache or whatever
558             #after you've upgraded it, so that the newest version is running after you
559             #upgrade, because otherwise the currently running version won't have whatever
560             #suecurity fixes that might have been in the previous release.
561             sub cmd_upgrade {
562 36     36   95 my $upgrade_name = shift;
563              
564 36         424 my ($P_upgrade,
565             $P_build_path,
566             $P_download_path,
567             $P_fetchware_package_path);
568              
569             ###BUGALERT### the or --force cmdline option will skip the checking of
570             #version numbers, and the one lookup() says to download will be installed
571             #regardless.
572 36         195 msg "Upgrading installed fetchware package [$upgrade_name].";
573              
574 36         318 $P_fetchware_package_path = determine_fetchware_package_path($upgrade_name);
575 36         187 vmsg <
576             Determined already installed fetchware package's path to be [$P_fetchware_package_path].
577             EOM
578              
579             # Parse out the Fetchwarefile from the fetchware package stored in the
580             # fetchware database directory.
581 36         72 my $fetchwarefile;
582 36 50       308 if ($P_fetchware_package_path =~ /\.fpkg$/) {
583 36         144 $fetchwarefile
584             = extract_fetchwarefile($P_fetchware_package_path);
585 36         221 vmsg "Extracted Fetchwarefile temporarily into [$fetchwarefile]";
586             } else {
587 0         0 die <
588             fetchware: fetchware upgrade failed to extract the Fetchwarefile from the
589             fetchware package that should be stored in fetchware's database.
590             EOD
591             }
592              
593             # Must parse the Fetchwarefile in the parent, so that the parent has access
594             # to the imported subroutines and modified fetchware configuration (%CONFIG)
595             # just as the child does.
596 36         295 parse_fetchwarefile($fetchwarefile);
597 36         186 vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
598              
599             # start() runs as root before the fork, because it uses
600             # App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
601             # subroutine uses a variable to store an open filehandle to a
602             # "fetchware.sem" semaphore file. This filehandle must stay open and locked
603             # using flock, because otherwise a "fetchware clean" run could delete the
604             # temporary directory out from under fetchware. Therefore, the parent must
605             # open this semaphore, because the child if it runs start() will close this
606             # file handle when it exits causing cleanup_tempdir() to freak out when
607             # end() is called.
608 36         278 my $temp_dir = start();
609              
610             # Drop privs, so only install() is called with root permissions
611             my $output = drop_privs(
612             sub {
613 0     0   0 my $write_pipe = shift;
614              
615             ###BUGALERT### Have lookup() replace the timestamp of what we should
616             #download too to make upgrade() be able to use the lookup_by_timestamp
617             #algorithm too, which is a better default anyway.
618 0         0 $P_download_path = lookup();
619              
620             # Call upgrade() to determine if the currently available version
621             # ($P_download_path) is newer than the currenlty installed version
622             # ($P_fetchware_package_path).
623 0         0 my $P_upgrade = upgrade($P_download_path, $P_fetchware_package_path);
624              
625 0 0       0 if ($P_upgrade) {
626 0         0 msg 'New version available upgrading now.';
627              
628 0         0 my $package_path = download($temp_dir, $P_download_path);
629              
630             ###BUGALERT### Add support for caching the key files gpg creates to the
631             #fetchwarefile, and for actually using them later on inside the fpkg.
632 0         0 verify($P_download_path, $package_path);
633              
634 0         0 $P_build_path = unarchive($package_path);
635 0         0 build($P_build_path);
636             } else {
637             # If a new version is not available, then the child should do
638             # nothing, and let the parent call end() to clean up below.
639              
640             # Set $P_build_path to something that will fail, and give a decent
641             # error message just in case.
642 0         0 $P_build_path = 'Build Path not set because upgrade not needed.';
643             }
644              
645             # Tell the parent, root, process the values of the variables the
646             # child calculated in this coderef, and write them across this pipe
647             # back to the parent
648 0         0 write_dropprivs_pipe($write_pipe,
649             $P_upgrade,
650             $P_build_path,
651             $P_download_path,
652             $P_fetchware_package_path
653             );
654 36         834 }, config('user')
655             ); # End drop_privs()
656              
657             # Read from the pipe the child, the drop_privs()ed process, writes to to
658             # read the necessary values that correspond to the variables that the
659             # child must communicate back to the parent, so the parent can continue
660             # processing as though no fork()ing or priv dropping took place.
661 36         695 ($P_upgrade,
662             $P_build_path,
663             $P_download_path,
664             $P_fetchware_package_path) = read_dropprivs_pipe($output);
665              
666             # Test if a new version is available again due to drop_priv() ending
667             # half way through this if statement.
668 36 100       162 if ($P_upgrade) {
669 6         89 install($P_build_path);
670              
671 6         12041 my $updated_fetchware_package_path
672             =
673             create_fetchware_package($fetchwarefile, cwd());
674 6         80 vmsg <
675             Created a new fetchware package for the newly installed upgraded fetchware
676             package [$updated_fetchware_package_path].
677             EOM
678              
679 6         49 uninstall_fetchware_package_from_database($P_fetchware_package_path);
680 6         29 vmsg 'Uninstalled the old fetchware package from the fetchware database.';
681              
682 6         26 my $installed_fetchware_package_path
683             = copy_fpkg_to_fpkg_database($updated_fetchware_package_path);
684 6         34 vmsg <
685             Installed new fetchware package to fetchware package database
686             [$installed_fetchware_package_path].
687             EOM
688              
689 6         58 end();
690              
691             # Return the path of the created and installed fetchware package.
692 6         54 return $installed_fetchware_package_path;
693             } else {
694              
695             # I only need the basename.
696 30         453 my $download_path_basename = file($P_download_path)->basename();
697 30         3941 my $upgrade_name_basename =
698             file( $P_fetchware_package_path)->basename();
699              
700             # Strip trailing garbage to normalize their names, so that they can be
701             # compared to each other.
702             ###BUGALERT### This comparision is quite fragile. Figure out a better way to
703             #do this!!!
704 30         1838 $upgrade_name_basename =~ s/\.fpkg$//;
705 30         296 $download_path_basename
706             =~ s/(\.(?:zip|tgz|tbz|txz|fpkg)|(?:\.tar\.(gz|bz2|xz|Z)?))$//;
707              
708 30         260 msg <
709             The latest version [$download_path_basename] is the same as the currently
710             installed version [$upgrade_name_basename]. So no upgrade is needed.
711             EOM
712             # Clean up temp dir.
713 30         585 end();
714              
715             # Return success! An upgrade isn't needed, because the latest version
716             # has been installed.
717 30         313 return 'No upgrade needed.';
718             }
719             }
720              
721              
722              
723             sub cmd_upgrade_all {
724             # Does *not* drop_privs(), because it calls cmd_upgrade(), which does, and
725             # it does not make any real sense to do it in cmd_upgrade_all(), because all
726             # it does is glob the fetchware_database_path(), and pass each element
727             # of that list to cmd_upgrade() to do the actual upgrading.
728 17 100   17   205 die <
729             fetchware: fetchware's upgrade-all command takes no arguments. Instead, it
730             simply loops through fetchware's package database, and upgrades all already
731             installed fetchware packages. Please rerun fetchware upgrade-all without any
732             arguments to upgrade all already installed packages, or run fetchware help for
733             usage instructions.
734             EOD
735              
736 16         100 msg 'Upgrading all installed fetchware packages.';
737              
738 16         92 my $fetchware_db_glob = catfile(fetchware_database_path(), '*');
739              
740 16         45 my @upgraded_packages;
741 16         942 for my $fetchware_package (glob $fetchware_db_glob) {
742 32         171 vmsg 'Looping over list of installed fetchware packages.';
743             ###BUGALERT### subize the 2 lines below, because I do this more than
744             #once.
745             # Strip each member of the fetchwarefile database down to just its name
746             # without any path garbage or fetchware package file extension, because
747             # cmd_upgrade() only accepts arguments of this format, and I do not want
748             # users to be able to provide a fetchware package as an argument to
749             # the fetchware upgrade command. I only want it capable of looking them
750             # up from its database.
751 32         223 $fetchware_package = file($fetchware_package)->basename();
752 32         2631 $fetchware_package =~ s/\.fpkg$//;
753             ###BUGALERT### Spit out a warning for anything in
754             #fetchware_database_path() that does not end .fpkg, which should be
755             #here.
756 32         235 vmsg "Upgrading installed fetchware package [$fetchware_package]";
757 32         201 push @upgraded_packages, cmd_upgrade($fetchware_package);
758             }
759              
760             ###BUGALERT### push the fetchware pacakge name and its cmd_upgrade() return
761             #value into a hash, and then return it or msg() it, to tell the user what
762             #was upgraded and what was not.
763             # Return 'No upgrade needed.' only if every package that was upgraded
764             # returned 'No upgrade needed.'.
765 16 100       111 if ( (grep { $_ eq 'No upgrade needed.'}
  32         177  
766             @upgraded_packages) eq @upgraded_packages) {
767 14         72 msg 'No packages need to be upgraded.';
768 14         191 return 'No upgrade needed.';
769             # Return a list of all packages that are not 'No upgrade needed.', which
770             # should not be returned.
771             } else {
772 2         7 my @upgraded_packages = grep { $_ ne 'No upgrade needed.' }
  4         11  
773             @upgraded_packages;
774 2         12 msg 'Packages were upgraded to newer versions:';
775 2         29 msg Dumper(\@upgraded_packages);
776 2         35 return @upgraded_packages;
777             }
778             }
779              
780              
781              
782              
783             ###BUGALERT### Fix the bug that prevents look from check for an installed
784             #package first, then a filename or fetchwarefile.
785             sub cmd_look {
786 2     2   17 my $filename = shift;
787              
788 2         8 my $P_look_path;
789              
790             my $fetchwarefile;
791 2 50       31 if ($filename =~ /\.fpkg$/) {
792 2         33 $fetchwarefile = extract_fetchwarefile($filename);
793 2         23 vmsg <
794             Extracting out Fetchwarefile from [$filename] to [$$fetchwarefile]
795             EOM
796             } else {
797 0         0 my $fh = safe_open($filename, <
798             fetchware: Fetchware failed to open the filename you specified to fetchware
799             install [$filename]. The OS error was [$!].
800             EOD
801 0         0 vmsg "Opened file [$filename] for slurping.";
802             # Add a \ to turn the slurped scalar into a scalar ref for calling
803             # parse_fetchwarefile() properly.
804 0         0 $fetchwarefile = \do {local $/; <$fh>};
  0         0  
  0         0  
805 0         0 vmsg "Slurped [$filename] into fetchware: [$$fetchwarefile]";
806             }
807              
808             # Must parse the Fetchwarefile in the parent, so that the parent has access
809             # to the imported subroutines and modified fetchware configuration (%CONFIG)
810             # just as the child does.
811 2         22 parse_fetchwarefile($fetchwarefile);
812 2         14 vmsg "Parsed Fetchwarefile [$$fetchwarefile].";
813              
814             # start() runs as root before the fork, because it uses
815             # App::Fetchware::Util's create_tempdir() to create a $temp_dir. This
816             # subroutine uses a variable to store an open filehandle to a
817             # "fetchware.sem" semaphore file. This filehandle must stay open and locked
818             # using flock, because otherwise a "fetchware clean" run could delete the
819             # temporary directory out from under fetchware. Therefore, the parent must
820             # open this semaphore, because the child if it runs start() will close this
821             # file handle when it exits causing cleanup_tempdir() to freak out when
822             # end() is called.
823             #
824             # Call start() with an option to have it keep the temp dir, and not
825             # have File::Temp clean it up with an END handler.
826 2         26 my $temp_dir = start(KeepTempDir => 1);
827              
828             # Drop privs to match up with cmd_install()'s behavior.
829             my $output = drop_privs(
830             sub {
831 0     0   0 my $write_pipe = shift;
832              
833 0         0 msg 'Downloading and unarchiving specified distribution.';
834              
835 0         0 my $download_url = lookup();
836              
837 0         0 my $package_path = download(cwd(), $download_url);
838              
839             ###BUGALERT### Add support for caching the key files gpg creates to
840             #the fetchwarefile, and for actually using them later on inside the
841             #fpkg.
842 0         0 verify($download_url, $package_path);
843              
844 0         0 my $build_path = unarchive($package_path);
845              
846             # end() is *not* run, because the point of look is to lookup,
847             # download, and unarchive, and then actually "look" at the files,
848             # and running end() would delete them.
849              
850             # Compose the $P_look_path. A simple catfile($temp_dir, $build_path)
851             # should work, but don't forget about drop_privs() extra temporary
852             # directory when run as root! To avoid this problem of the $P_look_path
853             # being wrong when run as root due to the extra temporary directory;
854             # instead, of a simple catfile(...) replace the last file portion of
855             # $package_path, with $build_path.
856 0         0 $P_look_path = catfile(dir($package_path)->parent(), $build_path);
857 0         0 msg <
858             Your package's contents are at [$P_look_path]. Please run [fetchware clean] to
859             delete these files and any other files fetchware may have left behind when you
860             are finished looking inside this package.
861             EOM
862              
863             # Tell the parent, root, process the values of the variables the
864             # child calculated in this coderef, and write them across this pipe
865             # back to the parent
866 0         0 write_dropprivs_pipe($write_pipe, $P_look_path);
867              
868             # Does not need to execute anything as root, because cmd_look() does not
869             # install anything or even call end(), because the suer is supposed to
870             # look at its output in the tempdir it prints out.
871 2         54 }, config('user')
872             ); # End drop_privs()
873              
874             # Read from the pipe the child, the drop_privs()ed process, writes to to
875             # read the necessary values that correspond to the variables that the
876             # child must communicate back to the parent, so the parent can continue
877             # processing as though no fork()ing or priv dropping took place.
878 2         53 ($P_look_path)
879             = read_dropprivs_pipe($output);
880              
881 2         25 return $P_look_path;
882             }
883              
884              
885              
886             sub cmd_list {
887 32     32   338 my @installed_packages = glob catfile(fetchware_database_path(), '*');
888            
889 32 50       204 if (@installed_packages == 0) {
890 0         0 msg 'No fetchware packages are currently installed.';
891 0         0 return;
892             }
893              
894 32         168 msg 'Listing all currently installed packages:';
895 32         115 for my $fetchware_package (@installed_packages) {
896             # Clean up $fetchware_package.
897 46         349 $fetchware_package = file($fetchware_package)->basename();
898 46         6130 $fetchware_package =~ s/\.fpkg$//;
899              
900 46         139 msg $fetchware_package;
901             }
902             }
903              
904              
905              
906              
907             ###BUGALERT### It could parse all installed Fetchwarefile's to obtain a listing
908             #of all temp_dirs that are used, and clean them as well!!!!
909             ###BUGALERT### Use --force to parse all temp_dir's in installed packages, and
910             #clean them too?? Let it receive an arg to a dir to clean of fetchware crap???
911             sub cmd_clean {
912             # If user specified no specific directories to clean, then clean the default
913             # system tmpdir().
914 5 50   5   3656 my @fetchware_temp_dirs = scalar @_ ? @_ : tmpdir();
915              
916 5         6 my @globbed_fetchware_temp_dirs;
917              
918             # Build a list of fetchware temporary directories across tmpdir() and any
919             # user provided paths on the command line.
920 5         16 for my $fetchware_temp_dir (@fetchware_temp_dirs) {
921             # What the user specified or tmpdir() must be a directory.
922 5 50       91 die <
923             fetchware: The specified directory [$fetchware_temp_dir] is not a directory or
924             does not exist. Please only specify directories that exist, and ones you have
925             read and write permission in. OS error [$!].
926             EOD
927              
928             # Store all of the fetchware-* temp dirs in @globbed_fetchware_temp_dirs
929             # for later processing.
930 5         643 for my $fetchware_file_or_dir (
931             glob(catfile($fetchware_temp_dir, 'fetchware-*')),
932             glob(catfile($fetchware_temp_dir, 'Fetchwarefile-*'))
933             ) {
934             # If it's a directory add it to the queue of directories to delete
935             # below.
936 16 100       141 if (-d $fetchware_file_or_dir) {
937 14         38 push @globbed_fetchware_temp_dirs, $fetchware_file_or_dir;
938             # If it's just a file just delete right away.
939             } else {
940             ###BUGALERT### Should I check if the current user has perms to
941             #delete the file before deleting it? What about root? Should
942             #root delete all files found even for other users? I'll go with
943             #the Unix default of just doing the operation, and dealing with
944             #the error message you receive to avoid the complexity of
945             #checking perms. Furthermore, what about Unix ACLs and Windows'
946             #ACL style perms? It's not worth dealing with that hassel.
947 2 50       107 unlink $fetchware_file_or_dir or die <
948             fetchware: Failed to unlink file [$fetchware_file_or_dir]. OS error [$!].
949             EOD
950 2         19 vmsg <
951             fetchware clean found and deleted file [$fetchware_file_or_dir].
952             EOM
953             }
954             }
955             }
956              
957 5 50       25 msg "fetchware clean found no fetchware temporary directories to clean"
958             if @globbed_fetchware_temp_dirs < 1;
959              
960             # Holds the number of directories that had errors when they were
961             # deleted.
962 5         5 my $num_remove_tree_errors = 0;
963             # Number of directories remove_tree removed successfully.
964 5         11 my $num_remove_tree_successes = 0;
965              
966              
967             # Loop over fetchware temp dirs, and delete the ones that are not locked.
968 5         6 for my $temp_dir (@globbed_fetchware_temp_dirs) {
969             # Try to lock the 'fetchware.sem' semaphore lock file
970              
971             # I annoying must open the file before I can see if I can lock it or
972             # not.
973 14         66 my $sem_lock_file = catfile($temp_dir, 'fetchware.sem');
974 14         19 my $fh_sem;
975 14 50       755 if (open $fh_sem, '>', $sem_lock_file) {
976 14         43 vmsg "Successfully created [fetchware.sem] semaphore lock file.";
977             } else {
978             # Test if the lockfile has the same owner uid as this running perl
979             # process, and if they differ skip deleting this one, because we
980             # lack the perms to do it anyway.
981 0 0       0 if ($> != (stat($sem_lock_file))[4]) {
982 0         0 msg "Skipping file [$sem_lock_file], because a different user created it.";
983 0         0 next;
984             } else {
985 0         0 die <
986             App-Fetchware-Util: Failed to create [$sem_lock_file] semaphore lock file! This
987             should not happen, because fetchware is creating this file in a brand new
988             directory that only fetchware should be accessing. You simply shouldn't see this
989             error unless some one is messing with fetchware, or perphaps there actually is a
990             bug? I don't know, but this just shouldn't happen. It's so hard to trigger it to
991             happen, it can't easily be tested in fetchware's test suite. OS error [$!].
992             EOD
993             }
994             }
995             # Now flock 'fetchware.sem.' This should
996             # Use LOCK_NB so flock won't stupidly wait forever and ever until
997             # he lock becomes available.
998             # If flock fails, don't die! Instead, just skip deleting this
999             # fetchware temporary directory, and go on to the next one.
1000 14 100       84 unless (flock $fh_sem, LOCK_EX | LOCK_NB) {
1001             # Flock failed, something else has the lock, print message, and skip
1002             # this directory, and go on to the next one.
1003 3         11 msg <
1004             [$temp_dir] locked by another fetchware process. Skipping.
1005             EOM
1006 3         33 next;
1007             }
1008              
1009             # Delete the whole $tempdir. Use error and result for File::Path's
1010             # experimental error handling, and set safe to true to avoid borking the
1011             # filesystem. This might be run as root, so it really could screw up
1012             # your filesystem big time! So set safe to true to avoid doing so.
1013 11         4355 remove_tree($temp_dir, {
1014             error => \my $err,
1015             result => \my $res,
1016             safe => 1} );
1017              
1018             # Parse remove_tree()'s insane error handling system. It's expirimental,
1019             # but it's been experimental forever, so I can't see it changing.
1020 11 50       42 if (@$err) {
1021 0         0 $num_remove_tree_errors++;
1022 0         0 for my $diag (@$err) {
1023 0         0 my ($file, $message) = %$diag;
1024 0 0       0 if ($file eq '') {
1025 0         0 warn "general error: $message\n";
1026             } else {
1027 0         0 warn "problem unlinking $file: $message\n";
1028             }
1029             }
1030             } else {
1031 11         51 vmsg "No errors encountered during removal of [$temp_dir]\n";
1032             }
1033              
1034 11 50       26 if (@$res) {
1035             # Keep track of each successfully removed directory.
1036 11         12 $num_remove_tree_successes++;
1037 11         47 vmsg "unlinked [$_]" for @$res;
1038             }
1039             }
1040              
1041             # Summarize success or failure for user, so he doesn't have to dig
1042             # through a bunch of error messages to see if it worked right.
1043 5 50       25 msg < 0;
1044             fetchware clean had [$num_remove_tree_errors] directories give errors.
1045             EOM
1046 5 100       36 msg < 0;
1047             fetchware clean successfully deleted [$num_remove_tree_successes] directories.
1048             EOM
1049              
1050             }
1051              
1052              
1053              
1054             sub cmd_help {
1055 6     6   2559 print <<'HELP';
1056             fetchware is a package manager for source code distributions. It gives you the
1057             ability to install, uninstall, and even upgrade your source code distributions
1058             just like you can with your binary packages using yum, apt-get, or slackpkg.
1059              
1060             To create a new package just use fetchware's "new" command such as:
1061             $ fetchware new
1062             And then answer the questions as best you can while fetchware takes your
1063             answers and creates a Fetchwarefile for you. If your program's needs seem to
1064             exceed the ability of fetchware's q&a configuration see perldoc App::Fetchware
1065             for instructions on manual Fetchwarefile configuration.
1066              
1067             USAGE:
1068             fetchware new|install|uninstall|upgrade|upgrade-all|list|look|clean|help
1069             --help|-h|-?|--version|-V|--verbose|-v|--quiet|-q]
1070             package-name
1071              
1072             COMMANDS:
1073             new - creates a new Fetchwarefile for use with fetchware.
1074             install - installs a fetchware package, which is a .tar.gz ending with
1075             .fpkg, which includes the source code distribution unmodified,
1076             but with an included Fetchwarefile. See perldoc fetchware.
1077             uninstall - uninstalls a fetchware package.
1078             upgrade - upgrades a fetchware package if a newer version is available.
1079             upgrade-all - upgrades *all* installed fetchware packages.
1080             list - lists all installed fetchware packages.
1081             look - downloads and unarchives a fetchware package for viewing.
1082             clean - deletes any left over messes caused by fetchware in your tempdir.
1083             help - prints this help message
1084             OPTIONS:
1085             --help|-h|-? - prints this help message.
1086             --version|-V - prints a version message.
1087             --verbose|-v - prints additional logging information.
1088             --quiet|-q - prints *no* logging invormation. Determine success or
1089             failure with fetchware's exit status. 0 = success. Non-zero = failure.
1090              
1091             For more information see perldoc fetchware and perldoc App::Fetchware.
1092             HELP
1093              
1094             ###BUGALERT###Consider actually adding dry run functionality.
1095             #--dry-run|-d - turns on dry run functionality causing fetchware to not
1096             #actually download or install or create any packages.
1097 6         1615 exit 0;
1098             }
1099              
1100              
1101              
1102              
1103              
1104              
1105              
1106             sub parse_fetchwarefile {
1107 169     169   261 my $fetchwarefile = shift;
1108              
1109             # Arg $fetchwarefile must be a SCALAR ref.
1110 169 50       641 die <
1111             fetchware: parse_fetchwarefile() was called with the wrong arguments. It only
1112             accepts and scalar references of the text of your fetchwarefile.
1113             EOD
1114              
1115             # Ensure the $fetchwarefile has a use App::Fetchware somewhere in it. And be
1116             # sure to support fetchware extensions such as App::FetchwareX::HTMLPageSync.
1117 169 50       1644 die <
1118             fetchware: The fetchwarefile you provided did not have a [use App::Fetchware]
1119             line in it. This line is required, because it is an important part of how
1120             fetchware uses Perl for its configuration file. Your fetchware file was.
1121             [$$fetchwarefile]
1122             EOD
1123              
1124             # Do the potentially evil eval. No Safe compartment or use ops is used. This
1125             # is one gigantic security hole; however, it is also how fetchware works :)
1126             #
1127             # safe_open() is used to ensure that the file the user provides is "safe" to
1128             # use, and is the limit of fetchware's safety features.
1129 169     25   15023 eval $$fetchwarefile;
  25     22   201  
  25     19   28  
  25     18   6108  
  22     17   227  
  22     15   28  
  22     14   4531  
  19     14   134  
  19     13   38  
  19         3691  
  18         188  
  18         42  
  18         4017  
  17         167  
  17         36  
  17         3946  
  15         134  
  15         44  
  15         3152  
  14         273  
  14         26  
  14         2858  
  14         108  
  14         17  
  14         2944  
  13         117  
  13         27  
  13         2414  
1130              
1131 169 50       310 die <
1132             fetchware: run-time error. fetchware failed to execute the Fetchwarefile
1133             [$$fetchwarefile] you provieded on the command line or that was packaged
1134             with your Fetchware package (*.fpkg). The error was [$@].
1135             EOD
1136              
1137              
1138             # Ensure that the specified App::Fetchware implementation exports the proper
1139             # subroutines.
1140 169         2502 my %api_subs = (
1141             start => 1,
1142             lookup => 1,
1143             download => 1,
1144             verify => 1,
1145             unarchive => 1,
1146             build => 1,
1147             install => 1,
1148             uninstall => 1,
1149             upgrade => 1,
1150             check_syntax => 1,
1151             end => 1,
1152             );
1153              
1154             # Determine if all of the @api_subs are in sublist, the list of all subs in
1155             # the current package.
1156             # Code adapted from Perl Cookbook pg. 129.
1157 169         199 my (%union, %intersection);
1158 169         1280 for my $element (keys %api_subs, sublist()) {
1159 27040 100       86853 $union{$element}++ && $intersection{$element}++;
1160             }
1161              
1162             # Compares the number of %intersection's to the number of %api_subs, and if
1163             # they're *not* equal throw an exception, so the user knows which API subs
1164             # are not set up right.
1165 169 50       1472 if ( (grep {exists $api_subs{$_} and exists $intersection{$_}
1166 1859 50 33     6869 and $api_subs{$_} eq $intersection{$_}}
1167             keys %api_subs) != scalar keys %api_subs) {
1168 0         0 my @missing_api_subs;
1169 0         0 for my $api_sub (keys %api_subs) {
1170 0 0 0     0 if (not exists $intersection{$api_sub}
      0        
1171             or not defined $intersection{$api_sub}
1172             or ($intersection{$api_sub} == 0)
1173             ) {
1174 0         0 push @missing_api_subs, $api_sub;
1175             }
1176             }
1177 0         0 die <
1178             fetchware: The App::Fetchware module you choose in your fetchwarefile does not
1179             properly export the necessary subroutines fetchware needs it to. These include:
1180             start(), lookup(), download(), verify, unarchive(), build(), install(),
1181             uninstall(), and end().
1182             The missing subroutines are [@missing_api_subs].
1183             EOD
1184             }
1185              
1186             # Call App::Fetchware's check_syntax() (or a App::Fetchware extension's).
1187 169         710 check_syntax();
1188              
1189 169         2092 return 'Evaled config file successfully';
1190             }
1191              
1192              
1193              
1194             sub create_fetchware_package {
1195 90     90   9198 my ($fetchwarefile,
1196             $unarchived_package_path,
1197             $dir_for_new_fpkg) = @_;
1198              
1199             # chdir() to my cwd's parent directory, because my cwd is currently on linux
1200             # /tmp/fetchware-kd883ejfe/program-1.2, and I need the program-1.2 part to
1201             # be in the archive's @file_list. This needs to happen even when dropping
1202             # privs, because drop_privs() chdir()'s before it forks putting both parent
1203             # and child in the same directory.
1204 90         174621 my $previous_cwd = cwd();
1205 90         175332 my $new_dir = dir(cwd())->parent();
1206 90 50       18345 chdir($new_dir) or die <
1207             fetchware: run-time error. Fetchware failed to change it's working
1208             directory to
1209             [$new_dir] from [$previous_cwd]. The os error was [$!].
1210             EOD
1211              
1212             # Turn something like /tmp/fetchware-djdjkd8382/package-1.2/Fetchware (with
1213             # the "Fetchwarefile" filename only sometimes being there) into just
1214             # "package-1.2"
1215 90         2777 my $pc = dir($unarchived_package_path);
1216 90         3132 my $last_dir = $pc->dir_list(-1, 1);
1217 90         1344 my $fetchware_package_name = "$last_dir.fpkg";
1218              
1219             # The dir the new fpkg goes in is the current working directory, or a user
1220             # provided alternate path to store it in.
1221 90   66     173192 $dir_for_new_fpkg //= cwd();
1222             # Calculate the full absolute path of the fetchware package I create below.
1223 90         751 my $fetchware_package_full_path
1224             =
1225             catfile($dir_for_new_fpkg, $fetchware_package_name);
1226              
1227             # Determine @file_list, because Archive::Tar does not just automatically
1228             # include *all* files like bin/tar does.
1229 90         160 my @file_list;
1230             find(sub {
1231 710     710   18493 push @file_list, $File::Find::name;
1232 90         10789 }, $unarchived_package_path);
1233              
1234             # Convert absolute filenames into relative filenames, because Archive::Tar
1235             # will use the exact filenames that you provide, so I need to remove the
1236             # unneeded machine specific paths from the paths that will be stored in the
1237             # fetchware package.
1238 90         1200 $_ = abs2rel($_) for @file_list;
1239              
1240 90         33079 my $tar = Archive::Tar->new();
1241              
1242             # Add the $fetchwarefile to the new fetchware package.
1243             #
1244             # Create a Archive::Tar::File object to represent the Fetchwarefile without
1245             # bothering to write it to disk, or use the Fetchwarefile, which may or may
1246             # not already be on the disk.
1247             #
1248             # Be sure to deref $fetchwarefile, becauses it's passed in as a ref.
1249 90 50       2187 my $tar_fetchwarefile
1250             =
1251             Archive::Tar::File->new(data => './Fetchwarefile', $$fetchwarefile)
1252             or die <
1253             fetchware: Failed to create a Archive::Tar::File object to represent your
1254             Fetchwarefile
1255             [$fetchwarefile]
1256 0         0 Archive::Tar error [@{[Archive::Tar->error()]}].
1257             EOD
1258              
1259 90 50       22210 $tar->add_files($tar_fetchwarefile) or die <
1260             fetchware: Failed to add your Fetchwarefile to fetchware's internal Archive::Tar
1261 0         0 object. Archive::Tar error [@{[Archive::Tar->error()]}].
1262             EOD
1263              
1264             # Add all of the other files to the Fetchware package.
1265 90 50       3260 $tar->add_files(@file_list) or die <
1266             fetchware: Failed to add all of your program's files to fetchware's internal
1267 0         0 Archvie::Tar object. Archive::Tar error [@{[Archive::Tar->error()]}].
1268             EOD
1269              
1270 90 50       173405 $tar->write($fetchware_package_full_path, COMPRESS_GZIP) or die <
1271             fetchware: Failed to write Archive::Tar's in-memeory tar file to disk.
1272 0         0 Archive::Tar error [@{[Archive::Tar->error()]}].
1273             EOD
1274              
1275             # chdir() back to original directory.
1276 90 50       957500 chdir($previous_cwd) or die <
1277             fetchware: run-time error. Fetchware failed to change its working directory from
1278 0         0 [@{[cwd()]}] to [$previous_cwd]. The os error was [$!].
1279             EOD
1280              
1281             # Return a fullpath version of $fetchware_package_name.
1282 90         2887 return $fetchware_package_full_path;
1283             }
1284              
1285              
1286              
1287             sub fetchware_database_path {
1288             # If user specifically specifies their own fetchware database path in their
1289             # fetchwarefile use it instead of the default one.
1290 408     408   334145 my $fetchware_database_path;
1291 408 100       2811 if (defined config('fetchware_db_path')) {
    100          
    50          
    0          
1292 2         6 $fetchware_database_path = config('fetchware_db_path');
1293             } elsif (defined $ENV{FETCHWARE_DATABASE_PATH}) {
1294 402         973 $fetchware_database_path = $ENV{FETCHWARE_DATABASE_PATH};
1295             } elsif (is_os_type('Unix', $^O)) {
1296             # If we're effectively root use a "system" directory.
1297 4 50       68 if ($> == 0) {
1298             # Fetchware is modeled slightly after Slackware's package manager,
1299             # which keeps its package database under /var/log/packages.
1300 4         11 $fetchware_database_path = '/var/log/fetchware';
1301             # else use a "user" directory.
1302             } else {
1303 0         0 $fetchware_database_path
1304             =
1305             File::HomeDir->my_dist_data('fetchware', { create => 1 });
1306             }
1307             } elsif ($^O eq "MSWin32") {
1308             # Load main Windows module to use to see if we're Administrator or not.
1309             BEGIN {
1310 33 50   33   21002 if ($^O eq "MSWin32")
1311             {
1312 0         0 require Win32;
1313 0         0 Win32->import(); # assuming you would not be passing arguments to "use Module"
1314             }
1315             }
1316 0 0       0 if (Win32::IsAdminUser()) {
1317             # Is this an appropriate default?
1318 0         0 $fetchware_database_path = 'C:\Fetchware';
1319             } else {
1320 0         0 $fetchware_database_path
1321             =
1322             File::HomeDir->my_dist_data('fetchware' , { create => 1 });
1323             }
1324             # Fall back on File::HomeDir's recommendation if not "Unix" or windows.
1325             ###BUGALERT### Is this appropriate for Mac OSX???? /Fetchware perhaps?????
1326             } else {
1327 0         0 $fetchware_database_path
1328             =
1329             File::HomeDir->my_dist_data('fetchware', { create => 1 });
1330             }
1331 408         2409 vmsg <
1332             Determined fetchware database path to be: [$fetchware_database_path]
1333             EOM
1334 408         23925 return $fetchware_database_path;
1335             }
1336              
1337              
1338              
1339             sub determine_fetchware_package_path {
1340 90     90   1412 my $fetchware_package = shift;
1341 90         497 my ($package, $filename, $line) = caller;
1342 90         324 my $fetchware_db_glob = catfile(fetchware_database_path(), '*');
1343              
1344             my @fetchware_package_filenames
1345 90         8654 =
1346             grep /$fetchware_package/, glob $fetchware_db_glob;
1347              
1348 90 50       451 die <
1349             fetchware: Fetchware failed to determine the fetchware package that is
1350             associated with the argument that you provided to fetchware
1351             [$fetchware_package]. In this case, fetchware only allows arguments for
1352             fetchware packages that have already been installed. Please run fetchware list
1353             to obtain a list of installed packages to choose from.
1354             EOD
1355              
1356             ###BUGALERT### Use Term::UI, and output a numbered list for the user to
1357             #choose from using a prompt, and then rerun upgrade with that argument.
1358 90 100       585 if (@fetchware_package_filenames > 1) {
1359             # Print beginning of message to STDERR.
1360 1         27 warn <
1361             fetchware: Too many installed packages match the argument you provided to the
1362             upgrade command. Your argument was [$fetchware_package], and the multiple
1363             results it returned were:
1364             EOW
1365              
1366             # Print modified array values to STDERR.
1367 1         6 for (@fetchware_package_filenames) {
1368 2         233 warn file($_)->basename(), "\n";
1369             }
1370              
1371             # Print closing of message to STDERR.
1372 1         115 die <
1373             Choose which package from the list above you want to upgrade, and rerun
1374             fetchware upgrade using it as the argument for the package you want to upgrade.
1375             EOD
1376             }
1377              
1378             # Return the first and only result.
1379 89         325 return $fetchware_package_filenames[0];
1380             }
1381              
1382              
1383              
1384             sub extract_fetchwarefile {
1385 170     170   424 my ($fetchware_package_path) = @_;
1386              
1387             # safe_open() the fetchware package path, which ends with .fpkg, but it
1388             # actually a .tar.gz.
1389 170         2226 my $fh = safe_open($fetchware_package_path, <
1390             fetchware: run-time error. fetchware failed to open the Fetchwarefile you
1391             specified on the command line [$fetchware_package_path]. Please check
1392             permissions and try again. See perldoc App::Fetchware. OS error [$!].
1393             EOD
1394              
1395             # Create a temporary file to write the ungzipped file to.
1396 169         2240 my ($output_fh, $gunzipped_path) = tempfile("fetchware-$$-XXXXXXXXXXX",
1397             TMPDIR => 1, UNLINK => 1);
1398              
1399 169 50       76988 gunzip($fh => $output_fh) or die <
1400             fetchware: IO::Uncompress::Gunzip::gunzip failed to un gzip
1401             [$fetchware_package_path]. Gunzip's error [$GunzipError].
1402             EOD
1403              
1404 169         266112 my $tar = Archive::Tar->new();
1405              
1406             # seek the $output_fh back to its beginning, so tar can reuse it.
1407 169         8096 seek $output_fh, 0, SEEK_SET;
1408              
1409             # read in the same output filehandle that gunzip() wrote the uncompressed tar
1410             # file to. This prevents any race conditions, and other users from messing
1411             # with our version of the open file.
1412 169 50       717 $tar->read($output_fh) or die <
1413             fetchware: Archive::Tar failed to read in the gunziped file [$gunzipped_path]
1414             that was previously gziped as [$fetchware_package_path].
1415 0         0 Archive::Tar error [@{[Archive::Tar->error()]}].
1416             EOD
1417              
1418 169 50       151878 my $fetchwarefile = $tar->get_content('./Fetchwarefile')
1419             or die <
1420             fetchware: run-time error. fetchware failed to extract your fetchware package's
1421             Fetchwarefile from the argument you specified on the command line [@ARGV].
1422 0         0 Archive::Tar error [@{[$tar->error()]}]. Please see perldoc App::Fetchware.
1423             EOD
1424              
1425              
1426             # Return a scalar ref of the $fetchwarefile that makes up the Fetchwarefile.
1427             # Do not
1428 169         12785 return \$fetchwarefile;
1429             }
1430              
1431              
1432              
1433             sub copy_fpkg_to_fpkg_database {
1434 89     89   185 my $fetchware_package_path = shift;
1435              
1436 89         283 my $fetchware_db_path = fetchware_database_path();
1437              
1438 89 100       1515 unless (-e $fetchware_db_path) {
1439             # Just use make_path() from File::Path to avoid having to check if
1440             # directories that contain the fetchware db directory have been created
1441             # or not. I doubt /var and /var/log won't exist on *nix systems, but
1442             # they probably don't on Mac OSX, which is kinda *nix.
1443 1 50       227 make_path($fetchware_db_path) or die <
1444             fetchware: run-time error. fetchware failed to create the directory that it
1445             needs to store its database of installed packages in [$fetchware_db_path].
1446             Library function error [$@].
1447             EOD
1448             }
1449 89 50       839 cp($fetchware_package_path, $fetchware_db_path) or die <
1450             fetchware: run-time error. fetchware failed to copy the specified
1451             fetchware package path [$fetchware_package_path] to [$fetchware_db_path]. Please
1452             see perldoc App::Fetchware.
1453             EOD
1454            
1455             # Return the full path to the fetchware package that has been copied.
1456 89         34403 my $fetchware_package_path_basename
1457             = dir($fetchware_package_path)->basename();
1458 89         6308 return catfile($fetchware_db_path, $fetchware_package_path_basename);
1459             }
1460              
1461              
1462              
1463             sub uninstall_fetchware_package_from_database {
1464 55     55   175 my $uninstall_package_name = shift;
1465              
1466             # Don't make preexisting absolute paths absolute again.
1467 55 50       442 $uninstall_package_name
1468             =
1469             catfile(fetchware_database_path(), $uninstall_package_name)
1470             unless file_name_is_absolute($uninstall_package_name);
1471              
1472 55 50       6460 unlink $uninstall_package_name
1473             or die <
1474             fetchware: Fetchware successfully uninstalled the fetchware package you
1475             requested [$uninstall_package_name], but it failed to also delete the
1476             corresponding fetchware package from its database Os error [$!].
1477             EOD
1478             }
1479              
1480              
1481              
1482             1;
1483              
1484             =pod
1485              
1486             =head1 NAME
1487              
1488             fetchware - Fetchware is a package manager for source code distributions.
1489              
1490             =head1 VERSION
1491              
1492             version 1.015
1493              
1494             =head1 SYNOPSIS
1495              
1496             =head2 Manpage synopsis.
1497              
1498             fetchware [-v | --verbose] [-q | --quiet] [-h | -? | --help]
1499             [-V | --version] []
1500              
1501             =head2 L
1502              
1503             fetchware new
1504              
1505             ... Read the printed explanations...
1506              
1507             ... And answer the questions fetchware asks you appropriately and then press
1508             enter.
1509              
1510             =head2 L
1511              
1512             fetchware install name-of-program.Fetchwarefile
1513              
1514             # And you can use a .fpkg fetchware package instead of a Fetchwarefile if
1515             # you have one.
1516             fetchware install name-of-program.fpkg
1517              
1518             =head2 L
1519              
1520             fetchware upgrade
1521              
1522             # Use fetchware list to see a list of already installed programs.
1523             fetchware list
1524              
1525             =head2 L installed fetchware packages.|/upgrade-all>
1526              
1527             fetchware upgrade-all
1528              
1529             =head2 L
1530              
1531             # Requires a "uninstall" make target, or customization of its Fetchwarefile
1532             # to specify what specific C will uninstall this package.
1533             fetchware uninstall
1534              
1535             =head2 L
1536              
1537             fetchware list
1538              
1539             # Pipe to grep if you want to search for something specific.
1540             fetchware list | grep
1541              
1542             =head2 L<"Look" inside a fetchware package.|/look>
1543              
1544             fetchware look |
1545              
1546             =head2 Put this in your /etc/cron.daily to make fetchware check for updates every night
1547              
1548             #!/bin/sh
1549             # Update all already installed fetchware packages.
1550             fetchware upgrade-all
1551              
1552             =head2 Or use crontab -e to put this in a user crontab if you don't want to fetchware system wide
1553              
1554             # Check for updates using fetchware every night at 2:30AM.
1555             # Minute Hour Day of Month Month Day of Week Command
1556             # (0-59) (0-23) (1-31) (1-12 or Jan-Dec) (0-6 or Sun-Sat)
1557             30 2 * * * fetchware upgrade-all
1558              
1559             =head1 MOTIVATION
1560              
1561             While sysadmining I liked to install my own compiled from source versions of
1562             popular programs like Apache, MySQL, or Perl without threading. However, doing
1563             so means that you have to manually recompile everytime a new security hole comes
1564             out, which is annoyingly frequent for Apache. So, fetchware was created to bring
1565             the power of package management to source code distributions.
1566              
1567             =head1 DESCRIPTION
1568              
1569             Fetchware is a package manager for source code distributions. It takes advantage
1570             of the fact that coincidentially I source code distributions follow the same
1571             conventions. Most use FTP and HTTP mirrors. Most use AutoTools or at least just
1572             a few commands that you execute in sequence to configure, build, and install the
1573             program.
1574              
1575             Fetchware harnesses these conventions to create a powerful and flexible package
1576             manager for source code distributions. It includes a simple, powerful, and
1577             flexible configuration syntax stored in files called Cs. These
1578             Cs specify the required mandatory configuration options,
1579             C, C, C, and a method of verifying your program. And
1580             they also specify any additional optional configuration options.
1581              
1582             To create a new Fetchwarefile to install a source code distribution use the
1583             L command. It will ask you a bunch of questions, and based
1584             on your answers and fetchware's assumptions fetchware will automagically create
1585             a new Fetchwarefile for you. Then it will ask if you would like fetchware to
1586             install it for you.
1587              
1588             If your source code distribution exceeds fetchware's new command's capabilities,
1589             then see the section L in
1590             L. It details how to create a Fetchwarefile manually in a text
1591             editor of your choice.
1592              
1593             Fetchware's commands are described next followed by its options. Following that
1594             is the section L, which describes in some detail how
1595             Fetchware does its magic, and documents how it all fits together.
1596              
1597             See L for more information on fetchware's Fetchwarefile syntax:
1598              
1599             =over
1600              
1601             =item *
1602              
1603             L - Describes
1604             how to create a appropriate Fetchwarefile manually using a text editor. This
1605             can be skipped. You should try fetchware's L first.
1606              
1607             =item *
1608              
1609             L - Shows how to
1610             use your newly created fetchwarefile with fetchware.
1611              
1612             =item *
1613              
1614             L - Details
1615             all of fetchware's configuration options that you can use to further customize
1616             your Fetchwarefile.
1617              
1618             =item *
1619              
1620             L - Shows you how to use
1621             embed Perl inside your Fetchwarefile to change fetchware's behavior as needed
1622             to make fetchware work with programs that use different conventions and
1623             assumptions that fetchware makes.
1624              
1625             =item *
1626              
1627             L - Details how to customize a
1628             Fetchwarefile for popular programs such as Apache, Nginx, PHP, MariaDB, and
1629             Postgres.
1630              
1631             =item *
1632              
1633             L - Details how to replace the
1634             module that implements fetchware's behavior, App::Fetchware, with a completely
1635             different module implementing completely different behavior. These fetchware
1636             extensions can even be shared with everyone else on CPAN. See
1637             L for an example.
1638              
1639             =back
1640              
1641             =head1 COMMANDS
1642              
1643             Each command maps to one operation a package manager can do. C,
1644             C, and C. There is also C to create new Fetchwarefiles
1645             without bothering with a text editor. And fetchware's way of upgrading all
1646             packages with C. Fetchware can also list its installed packages
1647             with C. And C is similar to Perl's original CPAN client's look
1648             command that downloads and unarchives the package, so you can "look" at it.
1649             The C command deletes any unused, leftover temporary files and
1650             directories Fetchware has unintentionally left in your system's temporary
1651             directory.
1652              
1653             =head2 new
1654              
1655             fetchware new
1656              
1657             C asks you a bunch of questions, and uses the answers you provide in
1658             addition to the contents of the directory listing fetchware downloads based on
1659             the C you give fetchware, to create a Fetchwarefile for you with all
1660             the mandatory options filled in. It also gives you the opportunity to add any
1661             additional options that you may want to use. C also gives you a chance to
1662             edit the Fetchwarefile it created for you manually in your editor. Set the
1663             C environment variable to pick which editor to use, or leave it empty,
1664             and fetchware will ask you what editor you would like to use.
1665              
1666             C finishes by asking if you would like fetchware to go ahead and install
1667             the Fetchwarefile it has just created for you. If you say yes, then fetchware
1668             will install it, or if you say no, fetchware will skip installing it for you,
1669             and print out the path to the Fetchwarefile it just created for you.
1670              
1671             You can install that Fetchwarefile later with:
1672              
1673             fetchware install path/to/your/some-program.Fetchwarefile
1674              
1675             For more details about fetchware's configuration files Fetchwarefiles see
1676             L
1677              
1678             =head2 install
1679              
1680             fetchware install
1681              
1682             fetchware install
1683              
1684             C parses the given Fetchwarefile or uses the embeded Fetchwarefile
1685             inside the fetchware package you specify. Then C Is your
1686             program as you specified in your Fetchwarefile.
1687              
1688             By default executes the commands:
1689              
1690             =over
1691              
1692             =item 1. C<./configure>
1693              
1694             =item 2. C
1695              
1696             =item 3. C
1697              
1698             =back
1699              
1700             You can use the Fetchwarefile configuration options C and
1701             C to customize how your program is build and installed.
1702             C specifies command line options that are added before C is
1703             run each time by Fetchware. And C specifies options to the
1704             first AutoTools command, C<./configure> that customizes how your program is
1705             built and installed.
1706              
1707             ...
1708             prefix '/usr/local';
1709             make_options '-j 4';
1710             configure_options '--enable-mpm --enable-so';
1711              
1712             Or, you can use Fetchwarefile's more generic configuraton options. You cannot
1713             use both C and any of C, C,
1714             C at the same time. C specifies alternate
1715             commands to build the program replacing C<./configure> and C, and you can
1716             also specify the C to replace C with some other
1717             command or commands that install your program.
1718              
1719             ...
1720             # build_commands and install_commands Fetchwarefile example.
1721             build_commands './Configure', 'make';
1722              
1723             install_commands 'make test', 'make install';
1724              
1725             ...
1726              
1727             See L for
1728             more details on these configuration options.
1729              
1730             =head2 upgrade
1731              
1732             fetchware upgrade
1733              
1734             C only upgrades already installed fetchware packages. You cannot
1735             upgrade a Fetchwarefile only an already installed fetchware package. To see a
1736             list of already installed fetchware packages run C, or pipe it
1737             through L
1738              
1739             fetchware list | grep
1740              
1741             =head2 upgrade-all
1742              
1743             fetchware upgrade-all
1744              
1745             C takes no arguments. Instead, it loops over the list of installed
1746             programs as shown in C and runs C on each one to upgrade all
1747             currently installed programs.
1748              
1749             =head2 uninstall
1750              
1751             C removes all components of a currently installed program.
1752             Afterwards, that program won't show up in a C anymore.
1753              
1754             =over
1755              
1756             =item B
1757              
1758             C is only capable of uninstalling programs that maintain a
1759             C make target. For example, C has a C, while
1760             Apache does not; therefore, without a prefix, fetchware can uninstall ctags, but
1761             it cannot uninstall Apache.
1762              
1763             The easiest way to be able to uninstall a program you install with fetchware
1764             that does not have a C is to use the C configuration
1765             option to use a separate prefix that everything is installed into this
1766             directory. Then you could specify a custom C that would
1767             delete everything in that directory:
1768              
1769             # Set prefix so apache can be easily uninstalled.
1770             prefix '/usr/local/apache';
1771              
1772             # Set uninstall_commands to delete everything in the prefix directory when
1773             # apache is uninstalled.
1774             uninstall_commands 'rm -r /usr/local/apache';
1775              
1776             Then when you uninstall apache, fetchware deletes its associated files, which
1777             may include your Web site's Web files, so back them up before hand if you need to
1778             keep them.
1779              
1780             The other way around this limitation is to use one of the following programs
1781             that use a cool C trick to watch what files C or its
1782             equivelent copy, and where they are copied to. Then these files are put into
1783             some sort of vendor-specific package such as apt-get or rpm.
1784              
1785             =over
1786              
1787             =item L
1788              
1789             Run like C will detect what files are copied where
1790             during installation, and will create a slackware, debian, or redhat package
1791             based on this information.
1792              
1793             =item L
1794              
1795             Provides very similar functionality to fetchware, but lacks fetchware's lookup
1796             and verify mechanisms. Includes its own package management functionality.
1797              
1798             =back
1799              
1800             =back
1801              
1802             As far as fetchware one day supporting some sort of hack like checkinstall or
1803             paco use, I'm against it. I'd prefer everyone just adding a C to
1804             their Makefiles. But it is on my todo list, and I may add similar functionality
1805             in the future, but I'll make no promises. Until then consider using the
1806             C and C hack.
1807              
1808             =head2 list
1809              
1810             fetchware list
1811              
1812             fetchware list | grep
1813              
1814             C just prints out the names of all fetchware packages that have been
1815             installed. It takes no arguments, and currently does not support listing only
1816             packages that match a certain criteria. However, you can just pipe it to
1817             L to using a regex to limit which packages you're looking for.
1818              
1819             =head2 look
1820              
1821             fetchware look
1822              
1823             C looks up the specified program using your C, downloads it,
1824             verifies it, and unarchives it. Then it prints out the location of the
1825             unarchived program, so you can take a look at its code, or install it manually
1826             if you would like to.
1827              
1828             =head2 clean
1829              
1830             fetchware clean
1831              
1832             C deletes all fetchware temporary files and directories to clean up your
1833             system temporary directory.
1834              
1835             You can also specify one or more arguments to C to specify what
1836             directories you want fetchware to search for fetchware's left over temp files to
1837             clean up.
1838              
1839             =head2 help
1840              
1841             Prints out a brief screen full of help messages reminding you of fetchware's
1842             command-line syntax.
1843              
1844             =head1 OPTIONS
1845              
1846             Fetchware's configuration file options are detailed below.
1847              
1848             Most of its options are stored in its configuration file. If none of these
1849             options suite what you need fetchware to do, consider using its Fetchwarefile
1850             to meet your needs. See
1851             L
1852              
1853             =head2 -v or --verbose
1854              
1855             fetchware -v install
1856              
1857             Fetchware's -v or --verbose option turns on verbose logging, which prints to
1858             STDOUT additional information regarding what fetchware is doing and how
1859             fetchware does it.
1860              
1861             If you have any problems with your Fetchwarefile, then you could turn on verbose
1862             mode to have fetchware log additional messages to STDOUT to aid in debugging
1863             your Fetchwarefile.
1864              
1865             =head2 -q or --quite
1866              
1867             fetchware -q upgrade
1868              
1869             The -q or --quite option tells fetchware to B log anything at all.
1870             Fetchware will even prevent any commands it runs from printing output to your
1871             terminal's STDOUT to avoid cluttering up your screen.
1872              
1873             Any warnings or error messages are still printed to STDERR.
1874              
1875             To determine if fetchware succeeded or failed you can test its exit status:
1876              
1877             fetchware -q upgrade
1878              
1879             echo $?
1880             0
1881              
1882             Fetchware exits 0 for success and non-zero for failure.
1883              
1884             =head2 -V or --version
1885              
1886             Prints out a short message and says what version of fetchware is running.
1887              
1888             =head2 -h or -? or --help
1889              
1890             Prints out a brief screen full of help messages reminding you of fetchware's
1891             command-line syntax.
1892              
1893             =head1 HOW FETCHWARE WORKS
1894              
1895             Fetchware works by having fetchware, the C file and
1896             App::Fetchware Perl package, do all of the "package manager" stuff:
1897              
1898             =over
1899              
1900             =item *
1901              
1902             Creating fetchware packages (create_fetchware_package())
1903              
1904             =item *
1905              
1906             Copying fetchware packages to the fetchware database
1907             (copy_fpkg_to_fpkg_database())
1908              
1909             =item *
1910              
1911             Creating and managing the fetchware database
1912             (determine_fetchware_package_path(), extract_fetchwarefile(),
1913             and fetchware_database_path())
1914              
1915             =item *
1916              
1917             uninstalling installed packages from the fetchware database
1918             (uninstall_fetchware_package_from_database())
1919              
1920             =back
1921              
1922             Fetchware I all of the specifics on how to install, upgrade, and
1923             uninstall the fetchware packages that fetchware manages to App::Fetchware or a
1924             App::Fetchware extension:
1925              
1926             =over
1927              
1928             =item *
1929              
1930             Implement Fetchware's new command's Q&A wizard interface (new() and new_install())
1931              
1932             =item *
1933              
1934             Checking Fetchwarefile's high-level syntax before execution (check_syntax())
1935              
1936             =item *
1937              
1938             Lookup to see if a new version is available (lookup())
1939              
1940             =item *
1941              
1942             Downloading the archive (download())
1943              
1944             =item *
1945              
1946             Verifying that the downloaded file is the same one the author uploaded (verify())
1947              
1948             =item *
1949              
1950             Unarchiving the package (unarchive())
1951              
1952             =item *
1953              
1954             Building and installing it (build() and install())
1955              
1956             =item *
1957              
1958             Uninstalling any already installed fetchware package (uninstall())
1959              
1960             =item *
1961              
1962             Determining if a newer version is available (upgrade())
1963              
1964             =item *
1965              
1966             Some before and after hooks (start() and end()).
1967              
1968             =back
1969              
1970             =head2 How fetchware's commands work
1971              
1972             Fetchware's commands work by using fetchware's API, described in the section
1973             L, to manage the package manager stuff. And
1974             fetchware I the heavy lifting of the steps needed to install,
1975             upgrade, and uninstall fetchware packages to L or a
1976             L.
1977              
1978             =over
1979              
1980             =item new
1981              
1982             C just asks the user a bunch of questions, and gives them an opportunity to
1983             answer questions. Then it uses your answers to generate a Fetchwarefile for you,
1984             so that you don't have to mess with creating one manually in a text editor.
1985              
1986             =item install
1987              
1988             Fetchware's install runs whatever fetchware API subroutines it needs to use, see
1989             the section L for more. Then, install() will parse
1990             a user provided Fetchwarefile or a Fetchwarefile fetchware finds in a fetchware
1991             package. The act of parsing the Fetchwarefile will import the App::Fetchware API
1992             subroutines into fetchware's namespace. This gives fetchware access to
1993             App::Fetchwares API or whatever extension may have been used. Then, the API
1994             subroutines are run providing whatever arguments they need and storing whatever
1995             their important return values may be in a variable to probably later be given to
1996             a later API subroutine as an argument.
1997              
1998             =item upgrade
1999              
2000             Cleverly reusues the same API subroutines that install uses, but in the middle
2001             of all that uses the upgrade() API subroutine to determine if a newer version is
2002             available. The upgrade() API subroutine allows Fetchware extensions to modify
2003             how Fetcwhare determines if a new version is available to support using git or
2004             something else to determine this.
2005              
2006             =item uninstall
2007              
2008             Uninstall parses the Fetcwharefile of the installed pacakges you specified. Then
2009             it runs whatever C you specified or the default,
2010             C if you specified none. Then the installed package is deleted
2011             from the fetchware database.
2012              
2013             =item list
2014              
2015             List just globs all files in the fetchware database directory as returned by
2016             fetchware_database_path(), and prints them to STDOUT. It does not let you
2017             specify a Perl regex, or a keyword or anything yet, because I'm currently unsure
2018             about the security ramifications of doing so. This feature may be added in the
2019             future.
2020              
2021             =item look
2022              
2023             look just does the first part of install(). It parses whatever Fetchwarefile it
2024             gets passed to it, then it does the start(), lookup(), download(), verify(), and
2025             unarchive() parts of install(). Then look prints the path of this directory, and
2026             exits.
2027              
2028             =item clean
2029              
2030             Clean just deletes all fetchware temp files and directories in the system
2031             temp_dir. These files and directories all start with C or
2032             C.
2033              
2034             =item help
2035              
2036             Just prints a simple, short, concise help message.
2037              
2038             =back
2039              
2040             =head2 How fetchware interfaces with App::Fetchware
2041              
2042             Fetchware interfaces with App::Fetchware using the parse_fetchwarefile() API
2043             subroutine. This subroutine simply eval()'s your Fetchwarefile and traps any
2044             errors, and then rethrows that exception adding a helpful message about what
2045             happened in addition to passing along the original problem from Perl.
2046              
2047             The act of eval()ing your Fetchwarefile causes Perl to parse and execute as it
2048             would any other Perl program. Only because its inside an eval any subroutines
2049             that are imported are imported in the the caller of eval()'s package. In this
2050             case fetchware.
2051              
2052             Fetchware takes advantage of this by requiring all Fetchwarefile's to have a
2053             C line. This line is what imports the default imports of
2054             App::Fetchware into fetchware, which include App::Fetchware's API subroutines.
2055              
2056             =head2 How fetchware intefaces with a fetchware extension
2057              
2058             As explained above parse_fetchwarefile() eval()'s your Fetchwarefile, and this
2059             causes Perl to parse and execute it. And any imports are imported into the
2060             caller's package, which is fetchware.
2061              
2062             That's how fetchware receives App::Fetchware's API subroutines, and it is also
2063             how fetchware receives a fetchware extensions API subroutines, the fetchware
2064             extension is simply use()d inside your Fetchwarefile instead of the default one
2065             of App::Fetchware. Instead of:
2066              
2067             use App::Fetchware;
2068              
2069             You would write:
2070              
2071             use App::FetchwareX::HTMLPageSync;
2072              
2073             To use the fetchware extension HTMLPageSync.
2074              
2075             =head1 INTERNAL SUBROUTINES IMPLEMENTING FETCHWARE COMMANDS
2076              
2077             Below are all of subroutines that implement fetchware's main command line
2078             options such as C or C and so on. These main
2079             subroutines are called based on the options you pass to fetchware from the
2080             command line.
2081              
2082             =head2 cmd_install()
2083              
2084             my $installed_fetchware_package_path = cmd_install($filename|@ARGV)
2085              
2086             cmd_install() implements fetchware's install command, which installs a package
2087             based on the specified Fetchwarefile or fetchware package.
2088              
2089             =head2 cmd_uninstall()
2090              
2091             my $uninstall_package_path = cmd_uninstall($uninstall_package_path|@ARGV);
2092              
2093             Uninstalls the given package. Note the given package does B have to be an
2094             exact match, but it does have to be unique if you have two versions of the same
2095             software installed such as httpd-2.2 and httpd-2.4. In that case you'd have to
2096             specify the version number as well.
2097              
2098             =over
2099              
2100             =item LIMITATION
2101              
2102             cmd_uninstall() unlike cmd_install() does not accept Fetchwarefiles as an
2103             argument to uninstall a fetchware package! Instead, you must provide the name
2104             and perhaps the name and version number of an already installed software
2105             package. For a list of such package names just run C to list all
2106             installed fetchware packages.
2107              
2108             =back
2109              
2110             =over
2111              
2112             =item NOTICE
2113              
2114             cmd_uninstall() does B call drop_privs() to drop privileges, because it
2115             needs root privileges to copy the installed fetchware package from the system
2116             level fetchware package database, and it needs root to actually be able to
2117             delete files in system level directories.
2118              
2119             =back
2120              
2121             =head2 cmd_new()
2122              
2123             my $fetchware_package_path = cmd_new($program_name);
2124              
2125             cmd_new() implements fetchware's new command. See
2126             L for detailed
2127             documentation for the specifics of the new command. This chunk of POD is about
2128             its implementation. cmd_new() calls the new() and new_install() App::Fetchware
2129             API subroutines, which in turn call a bunch of helper subroutines that implement
2130             the algorithm fetchware uses to build new Fetchwarefiles automagically for the
2131             user. The algorithm is dead stupid:
2132              
2133             =over
2134              
2135             =item 1. Ask for lookup_url & download it.
2136              
2137             =item 2. Analyze the contents of the output from the lookup_url.
2138              
2139             =item 3. Build the Fetchwarefile according to the output.
2140              
2141             =item 4. Ask other questions as needed.
2142              
2143             =back
2144              
2145             cmd_new() uses Term::UI, which in turn uses Term::ReadLine to implement the
2146             character based question and anwser wizard interface.
2147              
2148             cmd_new() also asks the user if they would like fetchware to build and install
2149             their new program based on their newly created Fetchwarefile. If they answer
2150             yes, it builds and installs it, and if not, cmd_new() returns the path to the
2151             created Fetchwarefile for them.
2152              
2153             =head2 cmd_upgrade()
2154              
2155             my $installed_fetchware_package_path = cmd_upgrade($upgrade_name);
2156             'No upgrade needed.' = cmd_upgrade($upgrade_name);
2157              
2158             Subroutine implementing Fetchware's upgrade command. This subroutine and command
2159             upgrade one and only one package that must be specified on the command line as
2160             well.
2161              
2162             =head2 cmd_upgrade_all()
2163              
2164             my @upgraded_packages = cmd_upgrade_all();
2165             'No upgrade needed.' = cmd_upgrade_all();
2166              
2167             Implements the C command, which upgrades all installed
2168             packages simply by looping over the fetchware database and running cmd_upgrade()
2169             on each one.
2170              
2171             Returns a list of the packages that were upgraded or the string
2172             'No upgrade needed.' if no packages were upgraded.
2173              
2174             =head2 cmd_look()
2175              
2176             my $look_path = cmd_look($filename);
2177              
2178             Looks up the latest version of the specified Fetchwarefile or fetchware package,
2179             and downloads, verifies, and unarchives the specified source code distribution,
2180             and then prints out the location of this archive.
2181              
2182             =over
2183              
2184             =item LIMITATION
2185              
2186             cmd_look() unarchive's the desired source code distribution into the same sort
2187             of temporary directory that fetchware itself uses during regular installs or
2188             upgrades. This cannot be changed, but after fetchware creates this directory it
2189             outputs its path, so that you can cd to it, and do whatever you need to it. You
2190             could also move it to where you want it to be as well. Remember to delete the
2191             fetchware-$PID-randomeletters style directory that it was stored in, or just run
2192             fetchware clean when you are finished working with it.
2193              
2194             =back
2195              
2196             =head2 cmd_list()
2197              
2198             cmd_list();
2199              
2200             Lists B of the packages fetchware has stored in its
2201             fetchware_database_path().
2202              
2203             =over
2204              
2205             =item LIMITATION
2206              
2207             There is no ability to limit this listing with a
2208             regex currently, so just pipe it to grep for now. Obviously in the future this
2209             ability could be added, but I'm currently unclear about its security
2210             ramifications. So for now, I'll hold out until I study what ack does.
2211              
2212             =back
2213              
2214             =head2 cmd_clean()
2215              
2216             cmd_clean(@ARGV);
2217              
2218             cmd_clean() implements fetchware's clean command, which deletes any left over
2219             fetchware temporary directories from your system's temorary directory. It
2220             cleverly uses locking to ensure that cmd_clean() does B delete a temporary
2221             directory that is still being used by a running fetchware process.
2222              
2223             cmd_clean() also deletes any temporary files that Fetchware uses that are
2224             regular files not directories. These start with either C or
2225             C for Fetchwarefiles cmd_new() creates for the user.
2226              
2227             flock() is used along with C from L. C gets an
2228             exclusive lock (only current process who got lock can access the file, and
2229             C, which does a non-blocking attempt to get a lock returning success at
2230             getting the lock or not getting the lock immediately. flock() is used on a semaphore
2231             file called C it is a useless empty file, that is only used for
2232             locking each fetchware temporary directory.
2233              
2234             flock() is used, because if the fetchware process using the lock closes the
2235             file or the process dies, exits itself, or is killed even sith C, the
2236             lock is released automatically by the OS and/or system libraries.
2237              
2238             cmd_clean() simply attempts to get a lock, and if it does it deletes that
2239             particular fetchware temporary directory. If it fails to get the exclusive lock,
2240             then it probably means that that fetchware temporary directory is still being
2241             used by another fetchware process, so that directory is skipped.
2242              
2243             create_tempdir() and cleanup_tempdir() create and lock the fetchware semaphore
2244             lock file, and close and unlock it as they are executed by start() and end().
2245              
2246             cmd_clean() via @ARGV, which run() calls it with, takes the arguments it
2247             receives as paths to whatever temporary directories it should clean.
2248              
2249             =head2 cmd_help()
2250              
2251             cmd_help();
2252              
2253             Prints a help message to C listing usage, all command options, and
2254             examples.
2255              
2256             And then Cs with an exit status of 0 indicating success.
2257              
2258             =head1 INTERNAL LIBRARY SUBROUTINES
2259              
2260             Below are the helper subroutines used by install(), uninstall(), new(), and so
2261             on.
2262              
2263             =head2 parse_fetchwarefile()
2264              
2265             'Evaled config file successfully' = parse_fetchwarefile(\$fetchwarefile);
2266              
2267             Eval's the \$fetchwarefile to effectively "parse" it.
2268              
2269             The only checking for the $fetchwarefile it does is that it is a scalar ref, and
2270             that it has at least one line beginning with C.
2271              
2272             It also checks to see that the eval of the provided $fetchwarefile actually
2273             winds up importing all of fetchware's API subroutines into fetchware's namespace.
2274              
2275             Then it runs check_syntax() to check the $fetchwarefile's syntax. Typically this
2276             only involves running config() a bunch of times to check that configuration
2277             options that don't belong together arn't used together.
2278              
2279             Returns true on success and dies with an error message if it fails.
2280              
2281             =head2 create_fetchware_package()
2282              
2283             # Most uses should just use this.
2284             my $fetchware_package_full_path
2285             =
2286             create_fetchware_package($fetchwarefile, $unarchived_package_path);
2287              
2288              
2289             # But some uses in test suites thanks to safe_open() need to be able to
2290             # specify where they should write the new fetchware package's path to.
2291             my $fetchware_package_full_path
2292             =
2293             create_fetchware_package($fetchwarefile,
2294             $unarchived_package_path
2295             $path_to_new_fpkg);
2296              
2297             Creates a fetchware package, ending in .fpkg, using $unarchived_package_path, as
2298             the directory to archive. Also, adds the C stored in the
2299             scalar $fetchwarefile argument to the fethware package that is created.
2300              
2301             You can specify an optional $path_to_new_fpkg, which will be a directory where
2302             create_fetchware_package() will write the new fetchware package to.
2303              
2304             Returns the full pathname to the fetchware package that was created.
2305              
2306             =head2 fetchware_database_path()
2307              
2308             my $fetchware_database_path = fetchware_database_path();
2309              
2310             Returns the correct path for the fetchware package database based on operating
2311             system and if super user or not.
2312              
2313             Also, supports user customizable fetchware database paths via the
2314             C environment variable, and the
2315             C Fetchwarefile configuration file. If both are
2316             specified C is prefered over
2317             C.
2318              
2319             =head2 determine_fetchware_package_path()
2320              
2321             my $fetchware_package_filename = determine_fetchware_package_path($fetchware_package);
2322              
2323             Looks up the $fetchware_package in C, and returns the
2324             full path to that given $fetchware_package.
2325              
2326             =over
2327             =item NOTE
2328             determine_fetchware_package_path() could potentially come up with more than one
2329             result if you have multiple versions of apache or other similarly named packages
2330             installed at the same time. If this happens an exception is thrown asking the
2331             user to specify a more specific name to query the fetchware database with.
2332              
2333             =back
2334              
2335             =head2 extract_fetchwarefile()
2336              
2337             my $fetchwarefile = extract_fetchwarefile($fetchware_package_path);
2338              
2339             Extracts out the Fetchwarefile of the provided fetchware package as specified by
2340             $fetchware_package_path, and returns the content of the Fetchwarefile as a
2341             scalar reference. Throws an exception if it it fails.
2342              
2343             =head2 copy_fpkg_to_fpkg_database()
2344              
2345             my $fetchware_package_path = copy_fpkg_to_fpkg_database($fetchwarefile_path);
2346              
2347             Installs (just copies) the specified fetchware package to the fetchware
2348             database, which is /var/log/fetchware on UNIX, C:\FETCHWARE on Windows with
2349             root or Administrator. All others are whatever L says. For Unix
2350             or Unix-like systems such as linux, L will put your own user
2351             fetchware database independent of the system-wide one in C
2352             in C<~/.local/share/Perl/dist/fetchware/>. This correctly follows some sort of
2353             standard. XDG or FreeDesktop perhaps?
2354              
2355             Creates the directory the fetchware database is stored in if it does not already
2356             exist.
2357              
2358             Returns the full path of the copied fetchware package.
2359              
2360             =head2 uninstall_fetchware_package_from_database()
2361              
2362             uninstall_fetchware_package_from_database($uninstall_package_name);
2363              
2364             Deletes the specified $uninstall_package_name from the fetchware package
2365             database. Throws an exception on error.
2366              
2367             =head1 THE FETCHWARE PACKAGE
2368              
2369             Like other package managers, fetchware has its own package format:
2370              
2371             =over
2372              
2373             =item *
2374              
2375             It ends with a C<.fpkg> file extension.
2376              
2377             =item *
2378              
2379             The package path, the location of the unarchived downloaded program, is simply
2380             archived again using L, and compressed with gzip.
2381              
2382             =item *
2383              
2384             But before the package path is archived the currently used Fetchwarefile is
2385             copied into the current directory, so that it is included with your fetchware
2386             package:
2387              
2388             ./Fetchwarefile
2389             httpd-2.2.x
2390             httpd-2.2.x/README
2391             httpd-2.2.x/INSTALL
2392             ....
2393              
2394             =back
2395              
2396             This simple package format was chosen instead of using a native package format
2397             such as a Microsoft C<.msi> package, Slackware format, rpm format, C<.deb>
2398             format, and so on. Thanks to distros like Gentoo and Arch, there are even more
2399             formats now. Also, each version of BSD has its own package format, and each
2400             version of commerical UNIX has its own package format too. ...It was easier to
2401             create a new format, then deal with all of the existing ones.
2402              
2403             This custom package format is unique, bare bones, and retains all of the power
2404             that installing the software from source manaully gives you.
2405              
2406             =over
2407              
2408             =item *
2409              
2410             Simple, and retains backward compatibility with manual installation.
2411              
2412             =item *
2413              
2414             The package format includes the source code, so it can be recompiled if you
2415             move the fetchware package to an architecture different than the one it was
2416             compiled on.
2417              
2418             =item *
2419              
2420             You can specify whatever configure and build options you want, so you're not
2421             stuck with whatever your distro's package maintainer has chosen.
2422              
2423             =back
2424              
2425             =head1 FAQ
2426              
2427             =head2 How does fetchware's database work?
2428              
2429             The design of fetchware's database was copied after Slackware's package database
2430             design. In Slackware each package is a file in C, an
2431             example: C. And inside that
2432             file is a list of files, whoose names are the locations of all of the files that
2433             this Slackware package installed. This format is really simple and flexible.
2434              
2435             Fetchware's database is simply the directory C (on Unix when
2436             run as root), or whatever File::HomeDir recommends. When packages are installed
2437             the final version of that package that ends with C<.fpkg> is copied to your
2438             fetchware database path. So after you install apache your fetchware database
2439             will look like:
2440              
2441             ls /var/log/fetchware
2442             httpd-2.4.3.fpkg
2443              
2444             It's not a real database or anything cool like that. It is simply a directory
2445             containting a list of fetchware packages that have been installed. However, this
2446             directory is managed by fetchware, and should not be messed with unless you are
2447             sure of what you are doing.
2448              
2449             =head2 What exactly is a fetchware package?
2450              
2451             A fetchware package is a gziped tar archive with its file extension changed to
2452             C<.fpkg>. This archive consists of the package that was downloaded in addition
2453             to your Fetchwarefile. For example.
2454              
2455             tar tvf httpd-2.4.3.fpkg
2456             ./Fetchwarefile
2457             httpd-2.4.3/README
2458             httpd-2.4.3/...
2459             ...
2460              
2461             See the section L to see all of the cool things you can
2462             do with them.
2463              
2464             =head1 ERRORS
2465              
2466             As with the rest of Fetchware, fetchware does not return any
2467             error codes; instead, all errors are die()'d if it's fetchware's
2468             error, or croak()'d if its the caller's fault.
2469              
2470             =head1 CAVEATS
2471              
2472             =over
2473              
2474             =item WINDOWS COMPATIBILITY
2475              
2476             Fetchware was written on Linux and tested by its author B on Linux.
2477             However, it should work on popular Unixes without any changes. But it has B
2478             been ported or tested on Windows yet, so it may work, or parts of it may work,
2479             but some might not. However, I have used File::Spec and Path::Class to support
2480             path and file manipulation accross all Perl-supported platorms, so that code
2481             should work on Windows. I intend to add Windows support, and add tests for Windows
2482             in the future, but for now it is unsupported, but may work. This is likely to
2483             improve in the future.
2484              
2485             =back
2486              
2487             =head1 SEE ALSO
2488              
2489             L, L,
2490             L, L,
2491             L, L,
2492             L
2493              
2494             =head1 AUTHOR
2495              
2496             David Yingling
2497              
2498             =head1 COPYRIGHT AND LICENSE
2499              
2500             This software is copyright (c) 2016 by David Yingling.
2501              
2502             This is free software; you can redistribute it and/or modify it under
2503             the same terms as the Perl 5 programming language system itself.
2504              
2505             =cut
2506              
2507             __END__