App-Fetchware

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

      This avoids any problems of weird "testing" packages remaining in your
      fetchware database due to a botched test or two.
    - Fixed a bug that caused Fetchwarefiles with no_install turned on to avoid
      installing your program, but they would still eroneously create and add a
      fetchware package to your fetchware database, which cause any upgrade-all
      runs to actually install this fetchware package. Now, no_install means no
      install.
    - Fixed all annoying "Use of uninitialized value" warnings in test suite,
      and am commited to not let any more back in. I love taking advantage of
      undef, but these warnings stink. Don't get too excited as some warnings
      were left, because they happen mostly when exceptions get thrown or
      directly because of how things are tested in the test suite. Furthermore, 
      I took my training wheels off, and finally ditched use diagnostics in each
      test file. I don't need it anymore, and it makes CPAN Tester reports extra
      annoying.

1.014     2014-09-12 20:55:16-04:00 America/New_York
    - Fixed more CPAN Tester FAIL reports.
        - Added File::HomeDir version 0.93+ as a dependency, because that's the
          first production release that supported the my_dist_data() method that
          Fetchware uses to store non-root fetchware database path.

bin/fetchware  view on Meta::CPAN

            cmd_help(@ARGV);
        } else {
            cmd_help(@ARGV);
        }
        # Exit success, because if any of the main subroutines run into any
        # problems they die() exceptions, which get caught in eval above, and
        # warn()ed below, and fetchware exits 1 for failure.
        vmsg 'Fetchware ran successfully! Exiting with status of 0 for success!';
        exit 0;
    };
    # If a fatal error was thrown print it to STDERR and exit indicating failure.
    if ($@) {
        # Set File::Temp's $KEEP_ALL so user can troubleshoot what happend
        # without having to bother to use --keep-all.
        $File::Temp::KEEP_ALL = 1;
        msg <<EOM;
Fetchware threw an exception! Exiting with an exit status of 1 for failure.
Fetchware failed inside directory [@{[cwd()]}].
EOM
        warn $@;
        exit 1;

bin/fetchware  view on Meta::CPAN


    # Determine if all of the @api_subs are in sublist, the list of all subs in
    # the current package.
    # Code adapted from Perl Cookbook pg. 129.
    my (%union, %intersection);
    for my $element (keys %api_subs, sublist()) {
        $union{$element}++ && $intersection{$element}++;
    }

    # Compares the number of %intersection's to the number of %api_subs, and if
    # they're *not* equal throw an exception, so the user knows which API subs
    # are not set up right.
    if ( (grep {exists $api_subs{$_} and exists $intersection{$_}
                and $api_subs{$_} eq $intersection{$_}}
                keys %api_subs) != scalar keys %api_subs) {
        my @missing_api_subs;
        for my $api_sub (keys %api_subs) {
            if (not exists $intersection{$api_sub}
                or not defined $intersection{$api_sub}
                or ($intersection{$api_sub} == 0)
            ) {

bin/fetchware  view on Meta::CPAN

=item help

Just prints a simple, short, concise help message.

=back

=head2 How fetchware interfaces with App::Fetchware

Fetchware interfaces with App::Fetchware using the parse_fetchwarefile() API
subroutine. This subroutine simply eval()'s your Fetchwarefile and traps any
errors, and then rethrows that exception adding a helpful message about what
happened in addition to passing along the original problem from Perl.

The act of eval()ing your Fetchwarefile causes Perl to parse and execute as it
would any other Perl program. Only because its inside an eval any subroutines
that are imported are imported in the the caller of eval()'s package. In this
case fetchware.

Fetchware takes advantage of this by requiring all Fetchwarefile's to have a
C<use App::Fetchware...;> line. This line is what imports the default imports of
App::Fetchware into fetchware, which include App::Fetchware's API subroutines.

bin/fetchware  view on Meta::CPAN


    my $fetchware_package_filename = determine_fetchware_package_path($fetchware_package);

Looks up the $fetchware_package in C<fetchware_database_path()>, and returns the
full path to that given $fetchware_package.

=over 
=item NOTE
determine_fetchware_package_path() could potentially come up with more than one
result if you have multiple versions of apache or other similarly named packages
installed at the same time. If this happens an exception is thrown asking the
user to specify a more specific name to query the fetchware database with.

=back

=head2 extract_fetchwarefile()

    my $fetchwarefile = extract_fetchwarefile($fetchware_package_path);

Extracts out the Fetchwarefile of the provided fetchware package as specified by
$fetchware_package_path, and returns the content of the Fetchwarefile as a

lib/App/Fetchware.pm  view on Meta::CPAN

package App::Fetchware;
our $VERSION = '1.016'; # VERSION: generated by DZP::OurPkgVersion
# ABSTRACT: App::Fetchware is Fetchware's API used to make extensions.
###BUGALERT### Uses die instead of croak. croak is the preferred way of throwing
#exceptions in modules. croak says that the caller was the one who caused the
#error not the specific code that actually threw the error.
use strict;
use warnings;

# CPAN modules making Fetchwarefile better.
use File::Spec::Functions qw(catfile splitpath splitdir file_name_is_absolute);
use Path::Class;
use Data::Dumper;
use File::Copy 'cp';

lib/App/Fetchware.pm  view on Meta::CPAN

#can B<only> be called one time per Fetchwarefile. If called more than one time
#will die with an error message.
#
#Function created with C<$CONFIG{$name} = $value;> inside the generated function that
#is named $name.
#
#=item * 'ONEARRREF'
#
#Generates a function with the name of _make_config_sub()'s first parameter that
#can B<only> be called one time per Fetchwarefile. And just like C<'ONE'> above
#if called more than once it will throw an exception. However, C<'ONEARRREF'> can
#be called with a list of values just like C<'MANY'> can, but it can still only
#be called once like C<'ONE'>.
#
#=item * 'MANY'
#
#Generates a function with the name of _make_config_sub()'s first parameter that
#can be called more than just once. This option is only used by fetchware's
#C<mirror()> API call.
#
#Function created with C<push @{$CONFIG{$name}}, $value;> inside the generated function that

lib/App/Fetchware.pm  view on Meta::CPAN

not possible. It is possible, and it does happen, so please properly configure
your Fetchwarefile to enable fetchware to verify that the downloaded software is
the same what the author uploaded.
EOP
                )
            ) {
                # If the user is ok with not properly verifying downloads, then
                # ignore the failure, and install anyway.
                $options{verify_failure_ok} = 'On';
            } else {
                # Otherwise, throw an exception.
                die <<EOD;
fetchware: Fetchware *must* be able to verify any software packages that it
downloads. The Fetchwarefile that you were creating could not do this, because
you failed to specify how fetchware can verify its downloads. Please rerun
fetchware new again, and this time be sure to specify a gpg_keys_url, specify
user_keyring to use your own gpg keyring, or answer yes to the question
regarding adding verify_failure_ok to your Fetchwarefile to make failing
verificaton acceptable to fetchware.
EOD
            }

lib/App/Fetchware.pm  view on Meta::CPAN

            vmsg <<EOM;
File [$file_listing->[$i][0]] has no version number in it. Ignoring.
EOM
            # And also skip adding this @iversionstring to @versionstrings,
            # because this @iversionstring is empty, and how do I sort an empty
            # array? Return undef--nope causes "value undef in sort fatal errors
            # and warnings." Return 0--nope causes a file with no version number
            # at beginning of listing to stay at listing, and cause fetchware to
            # fail picking the right version. Return -1--nope, because that's
            # hackish and lame. Instead, just not include them in the lookup
            # listing, and if that means that the lookup listing is empty throw
            # an exception.
            next;
        }
        # Add $i's version string to @versionstrings.
        push @versionstrings, [$i, @iversionstring];

        # And the sort below sorts them into highest number first order.
    }

   die <<EOD if @versionstrings == 0;

lib/App/Fetchware.pm  view on Meta::CPAN

failure is not fatal.
EOM
                return 'warned due to verify_failure_ok'
            }
        }
    } elsif (config('verify_method') =~ /gpg/i) {
        vmsg <<EOM;
You selected gpg cryptographic verification. Verifying now.
EOM
        ###BUGALERT### Should trap the exception {gpg,sha1,md5}_verify()
        #throws, and then add that error to the one here, otherwise the
        #error message here is never seen.
        gpg_verify($download_path)
            or die <<EOD unless config('verify_failure_ok');
App-Fetchware: run-time error. You asked fetchware to only try to verify your
package with gpg or openpgp, but they both failed. See the warning above for
their error message. See perldoc App::Fetchware.
EOD
    } elsif (config('verify_method') =~ /sha1?/i) {
        vmsg <<EOM;
You selected SHA1 checksum verification. Verifying now.

lib/App/Fetchware.pm  view on Meta::CPAN

        } else {
            die <<EOD;
App-Fetchware: check_config_options() only supports types 'BothAreDefined',
'Mandatory', and 'ConfigOptionEnum.' Please specify one of these, and try again.
EOD
        }
    }

    # Process @both_are_defined by checking if both of the elements in the
    # provided arrayrefs are "both defined", and if they are "both defined"
    # throw an exception.
    for my $AnB (@both_are_defined) {
        my ($A, $B) = @$AnB;

        my @A_defined;
        my @B_defined;

        # Check which ones are defined in both $A and $B
        {
            # the config() call will call the specified strings of which many
            # are expected to be uninitialized. Because we expect them to be

lib/App/Fetchware.pm  view on Meta::CPAN

            die <<EOD;
App-Fetchware: Your Fetchwarefile has incompatible configuration options.
You specified configuration options [@$A] and [@$B], but these options are not
compatible with each other. Please specifiy either [@$A] or [@$B] not both.
EOD
        }
    }


    # Process @mandatory options by checking if they're defined, and if not
    # throwing the specified exception.
    for my $AnB (@mandatory) {
        my ($option, $error_message) = @$AnB;

        die $error_message if not defined config($option);
    }


    # Process @config_option_enum.
    for my $AnB (@config_option_enum) {
        my ($option, $enumerations) = @$AnB;

lib/App/Fetchware.pm  view on Meta::CPAN

    hook verify => sub {
        my ($download_path, $package_path) = @_;
    
        # the latest tag is the download path see lookup.
        my $latest_tag = $download_path;
    
        # Run git verify-tag to verify the latest tag
        my $success = eval { run_prog('git verify-tag', "$latest_tag"); 1;};
    
        # If the git verify-tag fails, *and* verify_failure_ok has been turned on,
        # then ignore the thrown exception, but print an annoying message.
        unless (defined $success and $success) {
            unless (config('verify_failure_ok')) {
                msg <<EOM;
    Verification failure ok, becuase you've configured fetchware to continue even
    if it cannot verify its downloads. Please reconsider, because mirror and source
    code repos do get hacked. The exception that was caught was:
    [$@]
    EOM
            }
        }

lib/App/Fetchware.pm  view on Meta::CPAN


Use perls venerable Test::More, and whatever other Perl TAP testing modules you
need to be sure your fetchware extension works as expected.

L<Test::Fetchware/> has a few testing subroutines that fetchware itself uses
in its test suite that you may find helpful. These include:

=over

=item L<Test::Fetchware/eval_ok()> - A poor man's Test::Exception. Captures any
exceptions that are thrown, and compares them to the provided exception text or
regex.

=item L<Test::Fetchware/print_ok()> - A poor man's Test::Output. Captures
STDOUT, and compares it to the provided text.

=item L<Test::Fetchware/skip_all_unless_release_testing()> - Fetchware is a
package manager, but who wants software installed on their computer just to test
it? This subroutine marks test files or subtests that should be skipped unless
fetchware's extensive FETCHWARE_RELEASE_TESTING environement variables are set.
This funtionality is described next.

lib/App/Fetchware.pm  view on Meta::CPAN


All of new()'s API subroutines (everything in App::Fetchware's OVERRIDE_NEW
export tag) use extension_name() to deterime what the this extension should be
called. This is really only used in error messages and occasionally in some of
the questions that new's API subroutines will ask the user. But this subroutine
is important, because it allows extension authors to change all of the
C<App::Fetchware> references in the error messages to their own fetchware
extensions name.

extension_name() is a singleton, and can only be set once. After being set only
once any attempts to set it again will result in an exception being thrown.
Furthermore, any calls to it without arguments will result in it returning the
one scalar argument that was set the first time it was called.

=head3 opening_message();

    opending_message($opening_message);

opening_message() takes the specified $opening_message and just prints it to
C<STDOUT>. This subroutine may seem useless, you could just use print, but using
it instead of print helps document that what you're doing is printing the

lib/App/Fetchware.pm  view on Meta::CPAN


=item *

Under drop_privs() lookup() is executed in the child with reduced privileges.

=back

=back

C<lookup_method> can be either C<'timestamp'> or C<'versionstring'>, any other
values will result in fetchware throwing an exception.

=head2 lookup() API REFERENCE

The subroutines below are used by lookup() to provide the lookup functionality
for fetchware. If you have overridden the lookup() handler, you may want to use
some of these subroutines so that you don't have to copy and paste anything from
lookup.

App::Fetchware is B<not> object-oriented; therefore, you B<can not> subclass
App::Fetchware to extend it! 

lib/App/Fetchware.pm  view on Meta::CPAN


Uses the command-line program C<gpg> to cryptographically verify that the file
you download is the same as the file the author uploaded. It uses public-key
priviate-key cryptography. The author signs his software package using gpg or
some other OpenPGP compliant program creating a digital signature file with the
same filename as the software package, but usually with a C<.asc> file name
extension. gpg_verify() downloads the author's keys, imports them into
fetchware's own keyring unless the user sets C<user_keyring> to true in his
Fetchwarefile. Then Fetchware downloads a digital signature that usually
ends in C<.asc>. Afterwards, fetchware uses the gpg command line program to
verify the digital signature. gpg_verify returns true if successful, and throws
an exception otherwise.

You can use C<gpg_keys_url> to specify the URL of a file where the author has
uploaded his keys. And the C<gpg_sig_url> can be used to setup an alternative
location of where the C<.asc> digital signature is stored.

=head3 sha1_verify()

    'Package verified' = sha1_verify($download_path, $package_path);
    undef = sha1_verify($download_path, $package_path);

lib/App/Fetchware.pm  view on Meta::CPAN

unarchive_tar() for tar archives. It I<only> returns true for success. It
I<does not> return a list of extracted files like unarchive_tar() does, because
Archive::Zip's extractTree() method does not.

=head3 check_archive_files()

    my $build_path = check_archive_files($files);

Checks if all of the files in the archive are contained in one B<main>
directory, and spits out a warning if they are not. Also checks if
B<one or more> of the files is an absolute path, and if so it throws an
exception, because absolute paths could potentially overwrite important system
files messing up your computer.

=head2 build()

    'build succeeded' = build($build_path)

=over

=item Configuration subroutines used:

lib/App/Fetchware.pm  view on Meta::CPAN

Below are the subroutines that install() exports with its C<INSTALL_OVERRIDE>
export tag. fillmein!!!!!!!!  

=head3 chdir_unless_already_at_path()

chdir_unless_already_at_path() takes a $path as its argument, and determines if
that path is currently part of the current processes current working directory.
If it is, then it does nothing. Buf if the given $path is not in the current
working directory, then it is chdir()'d to.

If the chdir() fails, an exception is thrown.

=head2 uninstall()

    'uninstall succeeded' = uninstall($build_path)

=over

=item Configuration subroutines used:

=over

lib/App/Fetchware.pm  view on Meta::CPAN

check for this.

Also, unlike C<Mandatory> and C<ConfigOptionEnum> this syntax checker does not
take a string argument that specifies an error message, because it takes the two
other values that you specifiy, and uses them to fill in its own error message.

=item Mandatory

Is used to check for mandatory options, which just means that these options
absolutely must be specified in user's Fetchwarefiles, and if they are not, then
the provided error message is thrown as an exception.

=item ConfigOptionEnum

Tests that enumerations are valid. For example, C<lookup_method> can only take
two values C<timestamp> or C<versionstring>, and ConfigOptionEnum is used to
test for this.

=back

=head2 end()

lib/App/Fetchware.pm  view on Meta::CPAN

You can't fetchware does not have any log file support. However, you can simply
redirect STDOUT to a file to make your shell redirect STDOUT to a file for you.

    fetchware install <some-program.Fetchwarefile> > fetchware.log

This would not prevent any error messages from STDERR being printed to your
screen for that:

    fetchware install <some-program.Fetchwarefile> 2>&1 fetchware.log

And to throw away all messages use:

    fetchware -q install <some-progra.Fetchwarefile>

or use the shell

    fetchware install <some-program.Fetchwarefile 2>&1 /dev/null

=head2 Why don't you use Crypt::OpenPGP instead of the gpg command line program?

I tried to use Crypt::OpenPGP, but I couldn't get it to work. And getting gpg to

lib/App/Fetchware/Config.pm  view on Meta::CPAN

package App::Fetchware::Config;
our $VERSION = '1.016'; # VERSION: generated by DZP::OurPkgVersion
# ABSTRACT: Manages App::Fetchware's internal representation of Fetchwarefiles.
###BUGALERT### Uses die instead of croak. croak is the preferred way of throwing
#exceptions in modules. croak says that the caller was the one who caused the
#error not the specific code that actually threw the error.
use strict;
use warnings;

# Enable Perl 6 knockoffs, and use 5.10.1, because smartmatching and other
# things in 5.10 were changed in 5.10.1+.
use 5.010001;

use Carp 'carp';

lib/App/Fetchware/Config.pm  view on Meta::CPAN

the user to get (via config()), set (via config()), replace (via
config_replace()), delete (via config_delete()), delete all (via
__clear_CONFIG()), and even debug (via debug_CONFIG()) the internal
representation of the users Fetchwarefile.

=over

=item NOTICE
App::Fetchware::Config's represenation of your Fetchwarefile is per process. If
you parse a new Fetchwarefile it will conflict with the existing C<%CONFIG>, and
various exceptions may be thrown. 

C<%CONFIG> is a B<global> per process variable! You B<can not> try to maniuplate
more than one Fetchwarefile in memory at one time! It will not work! You can
however use __clear_CONFIG() to clear the global %CONFIG, so that you can use it
again. This is mostly just done in fetchware's test suite, so this design
limitation is not such a big deal.

=back

=head1 CONFIG SUBROUTINES

lib/App/Fetchware/Config.pm  view on Meta::CPAN

=head1 ERRORS

As with the rest of App::Fetchware, App::Fetchware::Config does not return any
error codes; instead, all errors are die()'d if it's App::Fetchware::Config's
error, or croak()'d if its the caller's fault.

=head1 BUGS 

App::Fetchware::Config's represenation of your Fetchwarefile is per process. If
you parse a new Fetchwarefile it will conflict with the existing C<%CONFIG>, and
various exceptions may be thrown. 

C<%CONFIG> is a B<global> per process variable! You B<can not> try to maniuplate
more than one Fetchwarefile in memory at one time! It will not work! You can
however use __clear_CONFIG() to clear the global %CONFIG, so that you can use it
again. This is mostly just done in fetchware's test suite, so this design
limitation is not such a big deal.

=head1 AUTHOR

David Yingling <deeelwy@gmail.com>

lib/App/Fetchware/CreateConfigOptions.pm  view on Meta::CPAN

#            )],
#        );
#    }
#
#Creates configuration options of the same types App::Fetchware uses. These
#are:
#
#=over
#
#=item 1. ONE - Stores one and only ever one value. If the configuration option
#is used more than once, an exception is thrown.
#
#=item 2. ONEARRREF - Stores one or more values. But only stores a list when
#provided a list when you call it such as
#C<install_commands './configure', 'make', 'make install'> would create a
#configuration option with three values. However, if a ONEARRREF is called more
#than once, and exception is also thrown.
#
#=item 3. MANY - Stores many values one at a time just like ONEARRREF, but can
#also be called any number of times, and  values are appended to any already
#existing ones.
#
#=item 4. BOOLEAN - Stores true or false values such as C<stay_root 'On'> or
#C<verify_failure_ok 1> or C<no_install 'True'>
#
#=back
#

lib/App/Fetchware/CreateConfigOptions.pm  view on Meta::CPAN

            temp_dir
        )],
    ;

Creates configuration options of the same types App::Fetchware uses. These
are:

=over

=item 1. ONE - Stores one and only ever one value. If the configuration option
is used more than once, an exception is thrown.

=item 2. ONEARRREF - Stores one or more values. But only stores a list when
provided a list when you call it such as
C<install_commands './configure', 'make', 'make install'> would create a
configuration option with three values. However, if a ONEARRREF is called more
than once, and exception is also thrown.

=item 3. MANY - Stores many values one at a time just like ONEARRREF, but can
also be called any number of times, and  values are appended to any already
existing ones.

=item 4. BOOLEAN - Stores true or false values such as C<stay_root 'On'> or
C<verify_failure_ok 1> or C<no_install 'True'>

=back

lib/App/Fetchware/CreateConfigOptions.pm  view on Meta::CPAN

=cut

__END__





##TODO##=head1 DIAGNOSTICS
##TODO##
##TODO##App::Fetchware throws many exceptions. These exceptions are not listed below,
##TODO##because I have not yet added additional information explaining them. This is
##TODO##because fetchware throws very verbose error messages that don't need extra
##TODO##explanation. This section is reserved for when I have to actually add further
##TODO##information regarding one of these exceptions.
##TODO##
##TODO##=cut

lib/App/Fetchware/Fetchwarefile.pm  view on Meta::CPAN

package App::Fetchware::Fetchwarefile;
our $VERSION = '1.016'; # VERSION: generated by DZP::OurPkgVersion
# ABSTRACT: Helps Fetchware extensions create Fetchwarefiles.
###BUGALERT### Uses die instead of croak. croak is the preferred way of throwing
#exceptions in modules. croak says that the caller was the one who caused the
#error not the specific code that actually threw the error.
use strict;
use warnings;

# Enable Perl 6 knockoffs, and use 5.10.1, because smartmatching and other
# things in 5.10 were changed in 5.10.1+.
use 5.010001;

use Text::Wrap 'wrap';

lib/App/Fetchware/Util.pm  view on Meta::CPAN

package App::Fetchware::Util;
our $VERSION = '1.016'; # VERSION: generated by DZP::OurPkgVersion
# ABSTRACT: Miscelaneous functions for App::Fetchware.
###BUGALERT### Uses die instead of croak. croak is the preferred way of throwing
#exceptions in modules. croak says that the caller was the one who caused the
#error not the specific code that actually threw the error.
use strict;
use warnings;

use File::Spec::Functions qw(catfile catdir splitpath splitdir rel2abs
    file_name_is_absolute rootdir tmpdir);
use Path::Class;
use Net::FTP;
use HTTP::Tiny;

lib/App/Fetchware/Util.pm  view on Meta::CPAN


                # Execute the coderef that is supposed to be done as non-root.
                $child_code->($writeonly);

                # Now close the pipe, to avoid creating a dead pipe causing a
                # SIGPIPE to be sent to the parent.
                close $writeonly or die <<EOD;
App-Fetchware-Util: Failed to close $writeonly pipe in child. Os error [$!].
EOD

                # Exit success, because failure is only indicated by a thrown
                # exception that bin/fetchware's main eval {} will catch, print,
                # and exit non-zero indicating failure.
                # Use POSIX's _exit() to avoid calling END{} blocks. This *must*
                # be done to prevent File::Temp's END{} block from attempting to
                # delete the temp directory that the parent still needs to
                # finish installing or uninstalling. The parent's END{} block's
                # will still be called, so this just turns off the child
                # deleting the temp dir not the parent.
                _exit 0;
            }

lib/App/Fetchware/Util.pm  view on Meta::CPAN

        ) {
            # ...Must chmod 700 so gpg's localized keyfiles are good.
            chmod(0700, $temp_dir) or die <<EOD;
App-Fetchware-Util: Fetchware failed to change the permissions of its temporary
directory [$temp_dir] to 0700. This should not happen, and is a bug, or perhaps
your system's temporary directory is full. The OS error was [$!].
EOD
        }

        $exception = $@;
        1; # return true unless an exception is thrown.
    } or die <<EOD;
App-Fetchware: run-time error. Fetchware tried to use File::Temp's tempdir()
subroutine to create a temporary file, but tempdir() threw an exception. That
exception was [$exception]. See perldoc App::Fetchware.
EOD

    $original_cwd = cwd();
    vmsg "Saving original working directory as [$original_cwd]";

    # Change directory to $CONFIG{TempDir} to make unarchiving and building happen

lib/App/Fetchware/Util.pm  view on Meta::CPAN


=head2 download_dirlist()

    my $dir_list = download_dirlist($url)

    my $dir_list = download_dirlist(PATH => $path)

Can be called with either a $url or a PATH parameter. When called with a $url
parameter, the specified $url is downloaded using no_mirror_download_dirlist(),
and returned if successful. If it fails then each C<mirror> the user specified
is also tried unitl there are no more mirrors, and then an exception is thrown.

If you specify a PATH parameter instead of a $url parameter, then that path is
appended to each C<mirror>, and the resultant url is downloaded using
no_mirror_download_dirlist().

=head2 no_mirror_download_dirlist()

    my $dir_list = no_mirror_download_dirlist($ftp_or_http_url)

Downloads a ftp or http url and assumes that it will be downloading a directory

lib/App/Fetchware/Util.pm  view on Meta::CPAN


=head2 download_file()

    my $filename = download_file($url)

    my $filename = download_file(PATH => $path)

Can be called with either a $url or a PATH parameter. When called with a $url
parameter, the specified $url is downloaded using no_mirror_download_file(),
and returned if successful. If it fails then each C<mirror> the user specified
is also tried unitl there are no more mirrors, and then an exception is thrown.

If you specify a PATH parameter instead of a $url parameter, then that path is
appended to each C<mirror>, and the resultant url is downloaded using
no_mirror_download_file().

=head2 no_mirror_download_file()

    my $filename = no_mirror_download_file($url)

Downloads one $url and assumes it is a file that will be downloaded instead of a

lib/App/Fetchware/Util.pm  view on Meta::CPAN






###BUGALERT### Actually implement croak or more likely confess() support!!!


##TODO##=head1 DIAGNOSTICS
##TODO##
##TODO##App::Fetchware throws many exceptions. These exceptions are not listed below,
##TODO##because I have not yet added additional information explaining them. This is
##TODO##because fetchware throws very verbose error messages that don't need extra
##TODO##explanation. This section is reserved for when I have to actually add further
##TODO##information regarding one of these exceptions.
##TODO##
##TODO##=cut



lib/App/FetchwareX/HTMLPageSync.pm  view on Meta::CPAN

    #chdir_to_build_path() can be put in :OVERRIDE_UNINSTALL!!! Which I can use
    #here.
        chdir $build_path or die <<EOD;
App-FetchwareX-HTMLPageSync: Failed to uninstall the specified package and specifically to change
working directory to [$build_path] before running make uninstall or the
uninstall_commands provided in the package's Fetchwarefile. Os error [$!].
EOD

        if ( defined config('destination_directory')) {
            # Use File::Path's remove_tree() to delete the destination_directory
            # thereby "uninstalling" this package. Will throw an exception that I'll
            # let the main eval in bin/fetchware catch, print, and exit 1.
            vmsg <<EOM;
Deleting entire destination directory [@{[config('destination_directory')]}].
EOM
            remove_tree(config('destination_directory'));
        } else {
            die <<EOD;
App-FetchwareX-HTMLPageSync: Failed to uninstall the specified App::FetchwareX::HTMLPageSync
package, because no destination_directory is specified in its Fetchwarefile.
This configuration option is required and must be specified.

lib/Test/Fetchware.pm  view on Meta::CPAN

    )],
);
# *All* entries in @EXPORT_TAGS must also be in @EXPORT_OK.
our @EXPORT_OK = map {@{$_}} values %EXPORT_TAGS;



sub eval_ok {
    my ($code, $expected_exception_text_or_regex, $test_name) = @_;
    eval {$code->()};
    # Test if an exception was actually thrown.
    if (not defined $@) {
        BAIL_OUT("[$test_name]'s provided code did not actually throw an exception");
    }
    
    # Support regexing the thrown exception's test if needed.
    if (ref $expected_exception_text_or_regex ne 'Regexp') {
        is($@, $expected_exception_text_or_regex, $test_name);
    } elsif (ref $expected_exception_text_or_regex eq 'Regexp') {
        like($@, qr/$expected_exception_text_or_regex/, $test_name);
    }

}



sub print_ok {
    my ($printer, $expected, $test_name) = @_;

    my $error;
    my $stdout;
    # Use eval to catch errors that $printer->() could possibly throw.
    eval {
        local *STDOUT;
        # Turn on Autoflush mode, so each time print is called it causes perl to
        # flush STDOUT's buffer. Otherwise a write could happen, that may not
        # actually get written before this eval closes, causing $stdout to stay
        # undef instead of getting whatever was written to STDOUT.
        $| = 1;
        open STDOUT, '>', \$stdout
            or $error = 'Can\'t open STDOUT to test cmd_upgrade using cmd_list';

lib/Test/Fetchware.pm  view on Meta::CPAN

using the CPAN dependency, because all it would take is a relatively simple
function that I could easily write and test. And their interfaces disagreed with
me. 

=head1 TESTING SUBROUTINES

=head2 eval_ok()

    eval_ok($code, $expected_exception_text_or_regex, $test_name);

Executes the $code coderef, and compares its thrown exception, C<$@>, to
$expected_exception_text_or_regex, and uses $test_name as the name for the test if
provided.

If $expected_exception_text_or_regex is a string then Test::More's is() is used,
and if $expected_exception_text_or_regex is a C<'Regexp'> according to ref(),
then like() is used, which will treat $expected_exception_text_or_regex as a
regex instead of as just a string.

=head2 print_ok()

lib/Test/Fetchware.pm  view on Meta::CPAN

=cut

__END__





##TODO##=head1 DIAGNOSTICS
##TODO##
##TODO##App::Fetchware throws many exceptions. These exceptions are not listed below,
##TODO##because I have not yet added additional information explaining them. This is
##TODO##because fetchware throws very verbose error messages that don't need extra
##TODO##explanation. This section is reserved for when I have to actually add further
##TODO##information regarding one of these exceptions.
##TODO##
##TODO##=cut

t/App-Fetchware-new  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
add_mirrors test file for testing add_mirrors() using Test::Expect has failed!
The details() method of this process's Test::Builder object should have been
printed above to help you figure out what went wrong.
EOD
}

t/App-Fetchware-new-fetchwarefile_name  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
fetchwarefile_name test file for testing fetchwarefile_name() using Test::Expect
has failed! The details() method of this process's Test::Builder object should
have been printed above to help you figure out what went wrong.
EOD
}

t/App-Fetchware-new-get_filter_option  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
get_filter_option test file for testing get_filter_option() using Test::Expect
has failed!  The details() method of this process's Test::Builder object should
have been printed above to help you figure out what went wrong.
EOD
}

t/App-Fetchware-new-get_mirrors  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
get_mirrors test file for testing get_mirrors() using Test::Expect has failed!
The details() method of this process's Test::Builder object should have been
printed above to help you figure out what went wrong.
EOD
}

t/App-Fetchware-new-get_verification  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
get_verification test file for testing get_verification() using Test::Expect has
failed!  The details() method of this process's Test::Builder object should have
been printed above to help you figure out what went wrong.
EOD
}

t/App-Fetchware-new-prompt_for_other_options  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
add_mirrors test file for testing add_mirrors() using Test::Expect has failed!
The details() method of this process's Test::Builder object should have been
printed above to help you figure out what went wrong.
EOD
}

t/App-FetchwareX-HTMLPageSync-new  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
new test file for testing new() using Test::Expect has failed! The details()
method of this process's Test::Builder object should have been printed above to
help you figure out what went wrong.
EOD
}

t/App-FetchwareX-HTMLPageSync-new-ask_about_keep_destination_directory  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
ask_about_keep_destination_directory test file for testing
ask_about_keep_destination_directory() using Test::Expect has failed! The
details() method of this process's Test::Builder object should have been printed
above to help you figure out what went wrong.
EOD
}

t/App-FetchwareX-HTMLPageSync-new-get_destination_directory  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
get_destination_directory test file for testing get_destination_directory() using Test::Expect has
failed!  The details() method of this process's Test::Builder object should have
been printed above to help you figure out what went wrong.
EOD
}

t/App-FetchwareX-HTMLPageSync-new-get_html_page_url  view on Meta::CPAN

# Spit out # of tests run.
done_testing();

# Print a bogus "prompt" to keep Expect from freaking out, because it presumes
# the prompt works like it does in a shell, but fetchware new is not a shell.
print "Bogus shell: \n";

# Because we're in a child process not the same one that is running the main
# test suite, if any tests fail this failure will not be reported back to our
# caller. So, we use Test::Builder to check if our tests have passed, and if
# they have we do nothing and return succes, but if not we throw an exception.
my $test = Test::Builder->new();
unless ($test->is_passing()) {
    diag explain \[$test->details()];
    die <<EOD;
get_html_page_url test file for testing get_html_page_url() using Test::Expect has
failed!  The details() method of this process's Test::Builder object should have
been printed above to help you figure out what went wrong.
EOD
}

t/Test-Fetchware.t  view on Meta::CPAN

    );
    # sort them to make the testing their equality very easy.
    @expected_testing_exports = sort @expected_testing_exports;
    my @sorted_testing_tag = sort @{$Test::Fetchware::EXPORT_TAGS{TESTING}};
    is_deeply(\@sorted_testing_tag, \@expected_testing_exports,
        'checked for correct exports.');
};


subtest 'test print_ok()' => sub {
    # Can't easily test the exceptions print_ok() throws, because they're if
    # open()ing a scalar ref fails, and if calling close() actually failes,
    # which can't easily be forced to fail.

    # Test print_ok() string message.
    my $test_message = 'A test message';
    print_ok(sub {print $test_message},
        $test_message, 'checked print_ok() string message success');

    # Test print_ok() regex.
    print_ok(sub {print $test_message},

t/bin-fetchware-Fetchwarefile.t  view on Meta::CPAN

hook verify => sub {
    my ($download_path, $package_path) = @_;

    # the latest tag is the download path see lookup.
    my $latest_tag = $download_path;

    # Run git verify-tag to verify the latest tag
    my $success = eval { run_prog('git verify-tag', "$latest_tag"); 1;};

    # If the git verify-tag fails, *and* verify_failure_ok has been turned on,
    # then ignore the thrown exception, but print an annoying message.
    unless (defined $success and $success) {
        unless (config('verify_failure_ok')) {
            msg <<EOM;
Verification failure ok, becuase you've configured fetchware to continue even
if it cannot verify its downloads. Please reconsider, because mirror and source
code repos do get hacked. The exception that was caught was:
[$@]
EOM
        }
    }

t/bin-fetchware-uninstall.t  view on Meta::CPAN

    like($fetchware_package_path, qr/$uninstalled_package_path/,
        'check cmd_install(Fetchware) success.');
};


subtest 'test cmd_uninstall() failure' => sub {
    skip_all_unless_release_testing();

    # Save cwd to chdir to it later, because the uninstall exceptions that I'm
    # trapping below do *not* chdir back to the main fetchware directory after
    # they are thrown, so I must do it manually.
    my $original_cwd = cwd();

###BUGALERT### The exception below cannot be tested, because the condition it
#tests for is tested previously as tested in the test below. Remove throwing
#this exception, or move throwing it to cmd_uninstall() from
#determine_fetchware_package_path().
###    eval_ok(sub {cmd_uninstall('fetchware-test' . rand(2838382828282))},
###        <<EOE, 'checkec cmd_uninstall() package existence
###fetchware: The argument you provided to fetchware upgrade was not found in
###fetchware's package database. To get a list of available packages to upgrade
###just run the fetchware list command to list all installed packages. Select one
###of those to upgrade, and then rerun fetchware upgrade.
###EOE

    # Test for correct error if a package isn't installed.



( run in 0.461 second using v1.01-cache-2.11-cpan-496ff517765 )