File Coverage

bin/fetchware
Criterion Covered Total %
statement 354 458 77.2
branch 75 138 54.3
condition 5 18 27.7
subroutine 58 64 90.6
pod n/a
total 492 678 72.5


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