File Coverage

bin/fetchware
Criterion Covered Total %
statement 359 463 77.5
branch 78 138 56.5
condition 6 15 40.0
subroutine 59 65 90.7
pod n/a
total 502 681 73.7


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