App-Fetchware

 view release on metacpan or  search on metacpan

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';
use HTML::TreeBuilder;
use Scalar::Util qw(blessed looks_like_number);
use Digest::SHA;
use Digest::MD5;
#use Crypt::OpenPGP::KeyRing;
#use Crypt::OpenPGP;
use Archive::Tar;
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
use Cwd 'cwd';
use Sub::Mage;
use URI::Split qw(uri_split uri_join);
use Text::ParseWords 'quotewords';
use File::Temp 'tempfile';
use Term::ReadLine;
use Term::UI;

use App::Fetchware::Util ':UTIL';
use App::Fetchware::Config ':CONFIG';

# 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;

# Set up Exporter to bring App::Fetchware's API to everyone who use's it
# including fetchware's ability to let you rip into its guts, and customize it
# as you need.
use Exporter qw( import );
# By default fetchware exports its configuration file like subroutines.
#
# These days popular dogma considers it bad to import stuff without being asked
# to do so, but App::Fetchware is meant to be a configuration file that is both
# human readable, and most importantly flexible enough to allow customization.
# This is done by making the configuration file a perl source code file called a
# Fetchwarefile that fetchware simply executes with eval.
our @EXPORT = qw(
    program
    filter
    temp_dir
    fetchware_db_path
    user
    prefix
    configure_options
    make_options
    build_commands
    install_commands
    uninstall_commands
    lookup_url
    lookup_method
    gpg_keys_url
    gpg_sig_url
    sha1_url
    md5_url
    user_agent
    verify_method
    no_install
    verify_failure_ok
    user_keyring
    stay_root
    mirror

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

    
    # Must add the developers public keys to my own keyring. These keys are
    # availabe from http://nginx.org/en/pgp_keys.html Do this with:
    # gpg \
    # --fetch-keys http://nginx.org/keys/aalexeev.key\
    # --fetch-keys http://nginx.org/keys/is.key\
    # --fetch-keys http://nginx.org/keys/mdounin.key\
    # --fetch-keys http://nginx.org/keys/maxim.key\
    # --fetch-keys http://nginx.org/keys/sb.key\
    # --fetch-keys http://nginx.org/keys/glebius.key\
    # --fetch-keys http://nginx.org/keys/nginx_signing.key
    # You might think you could just set gpg_keys_url to the nginx-signing.key key,
    # but that won't work, because like apache different releases are signed by
    # different people. Perhaps I could change gpg_keys_url to be like mirror where
    # you can specify more than one option?
    user_keyring 'On';
    # user_keyring specifies to use the user's own keyring instead of fetchware's.
    # But fetchware drops privileges by default using he user 'nobody.' nobody is
    # nobody, so that user account does not have a home directory for gpg to read a
    # keyring from. Therefore, I'm using my own account instead.
    user 'dly';
    # The other option, which is commented out below, is to use root's own keyring,
    # and the no_install option to ensure that root uses its own keyring instead of
    # nobody's.
    # noinstall 'On';
    verify_method 'gpg';

=back

=head2 PHP Programming Language

PHP annoyingly uses a custom Web application on each of its mirror sites to
serve HTTP downloads. No simple directory listing is available. Therefore, to
use php with fetchware, custom C<lookup>, C<download>, and C<verify> hooks are
needed that override fetchware's internal behavior to customize fetchware as
needed so that it can work with how PHP's site is up.

The C<lookup> hook downloads and parses the L<http://www.php.net/downloads.php>
page, which lists files availabe for download. This file is parsed using
L<HTML::TreeBuilder> to determine the latest version. The MD5 sum is also parsed
out to verify the downloaded file as well.

The C<download> hook is only needed, because http_download_file() presumes that
the last part of the path is the filename you're downloading. And this is
annoyingly not the case with the way PHP has its downloading system set up.

The C<verify> hook just uses L<Digest::MD5> to calculate the md5sum of the
downloaded file, and compares it with the one C<lookup> parses out.

=over

    use App::Fetchware qw(
        :OVERRIDE_LOOKUP
        :OVERRIDE_DOWNLOAD
        :OVERRIDE_VERIFY
        :DEFAULT
    );
    use App::Fetchware::Util ':UTIL';
    use HTML::TreeBuilder;
    use URI::Split qw(uri_split uri_join);
    use Data::Dumper;
    use HTTP::Tiny;
    
    program 'php';
    
    lookup_url 'http://us1.php.net/downloads.php';
    mirror 'http://us1.php.net';
    mirror 'http://us2.php.net';
    mirror 'http://www.php.net';
    
    # php does *not* use a standard http or ftp mirrors for downloads. Instead, it
    # uses its Web site, and some sort of application to download files using URLs
    # such as: http://us1.php.net/get/php-5.5.3.tar.bz2/from/this/mirror
    #
    # Bizarrely a URL like
    # http://us1.php.net/get/php-5.5.3.tar.bz2/from/us2.php.net/mirror
    # gets you the same page, but on a different mirror. Weirdly, these are direct
    # downloads without any HTTP redirects using 300 codes, but direct downloads.
    # 
    # This is why using fetchware with php you needs a custom lookup handler.
    # The files you download are resolved to a [http://us1.php.net/distributions/...]
    # directory, but trying to access a apache styple auto index at that url fails
    # with a rediret back to downloads.php.
    my $md5sum;
    hook lookup => sub {
        die <<EOD unless config('lookup_url') =~ m!^http://!;
    php.Fetchwarefile: Only http:// lookup_url's and mirrors are supported. Please
    only specify a http lookup_url or mirror.
    EOD
    
        msg "Downloading lookup_url [@{[config('lookup_url')]}].";
        my $dir_list = download_dirlist(config('lookup_url'));
    
        vmsg "Parsing HTML page listing php releases.";
        my $tree = HTML::TreeBuilder->new_from_content($dir_list);
    
        # This parsing code assumes that the latest version of php is the first one
        # we find, which seems like a dependency that's unlikely to change.
        my $download_path;
        $tree->look_down(
            _tag => 'a',
            sub {
                my $h = shift;
                
                my $link = $h->as_text();
    
                # Is the link a php download link or something to ignore.
                if ($link =~ /tar\.(gz|bz2|xz)|(tgz|tbz2|txz)/) {
    
                    # Set $download_path to this tags href, which should be
                    # something like: /get/php-5.5.3.tar.bz2/from/a/mirror
                    if (exists $h->{href} and defined $h->{href}) {
                        $download_path = $h->{href};
                    } else {
                        die <<EOD;
    php.Fetchwarefile: A path should be found in this link [$link], but there is no
    path it in. No href [$h->{href}].
    EOD
                    }
    
                    # Find and save the $md5sum for the verify hook below.



( run in 0.725 second using v1.01-cache-2.11-cpan-39bf76dae61 )