App-Fetchware

 view release on metacpan or  search on metacpan

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

sub download_dirlist {
    my %opts;
    my $url;
    # One arg means its a $url.
    if (@_ == 1) {
       $url = shift;
    # More than one means it's a PATH, and if it's not a path...
    } elsif (@_ == 2) {
        %opts = @_;
        # Or your param wasn't PATH
        if (not exists $opts{PATH} and not defined $opts{PATH}) {
            # Use goto for cool old-school C-style error handling to avoid copy
            # and pasting or insane nested ifs.
            goto PATHERROR;
        }
    # ...then it's an error.
    } else {
        PATHERROR: die <<EOD;
App-Fetchware-Util: You can only specify either PATH or URL never both. Only
specify one or the other when you call download_dirlist().
EOD
    }

    # Ensure the user has specified a mirror, because otherwise download_file()
    # will try to just download a path, and that's not going to work.
    die <<EOD if not config('mirror') and exists $opts{PATH};
App-Fetchware-Util: You only called download_dirlist() with just a PATH
parameter, but also failed to specify any mirrors in your configuration. Without
any defined mirrors download_dirlist() cannot determine from what host to
download your file. Please specify a mirror and try again.
EOD

    # Set up our list of urls that we'll try to download the specified PATH or
    # URL from.
    my @urls = config('mirror') if defined config('mirror');
    if (exists $opts{PATH}
        and defined $opts{PATH}
        and $opts{PATH}) {
        # The PATH option means that $url is not a full blown URL, but just a
        # path without a hostname or scheme portion.
        # Therefore, we append $url, because the PATH option means it's actually
        # just a path, so we append it to each @url.
        for my $mirror_url (@urls) {
            # Use URI to replace the current path with the one the caller
            # specified in the $url parameter.
            my ($scheme, $auth, undef, undef, undef) = uri_split($mirror_url);
            $mirror_url = uri_join($scheme, $auth, $opts{PATH}, undef, undef);
        }
    } elsif (defined $url
        and $url) {
        # Add $url to @urls since it too has a hostname. And use unshift
        # to put it in the first position instead of last if you were to use
        # push.
        unshift @urls, $url;

        # I must parse out the path portion of the specified URL, because this
        # path portion will be appended to the mirrors you have specified.
        my $url_path = ( uri_split($url) )[2];
        for my $mirror_url (@urls) {
            # If the $mirror_url has no path...
                my ($scheme, $auth, $path, $query, $frag) =
                    uri_split($mirror_url);
            ###BUGALERT### Should check below also check for $query and $frag,
            #and if the mirror has specified those to include those too???
            if ($path eq '') {
                #...then append $url's path.
                ###BUGALERT## As shown before I was using URI's much nicer
                #interface, but it was deleting the path instead of replacing
                #the path! I tried reproducing this with a small test file, but
                #it worked just fine in the small test file. So, it must be some
                #really weird bug to fail here, but work in a smaller test file.
                #I don't know try replacing all of the URI::Split calls with the
                #equivelent URI->path() calls, and you'll get the weird bug.
                #$mirror_url->path($url_path);
                $mirror_url =
                    uri_join($scheme, $auth, $url_path, $query, $frag);
            # But if the $mirror_url does have a path...
            } else {
                #...Then keep the mirrors path intact.
                #
                # Because if you specify a path when you define that mirror
                # chances are you did it, because that mirror stores it in a
                # different directory. For example Apache is /apache on some
                # mirrors, but apache.hostname on other mirrors.
            }
        }
    }

    my $dirlist;

    for my $mirror_url (@urls) {
        eval {
            msg "Attempting to download [$mirror_url].";
            # Try the mirror_url directly without trying any mirrors.
            $dirlist = no_mirror_download_dirlist($mirror_url);
        };
        if ($@) {
            msg "Directory download attempt failed! Error was[";
            print $@;
            msg "].";
        }

        # Skip the rest of the @urls after we successfully download the $url.
        if (defined $dirlist) {
            msg "Successfully downloaded the directory listing.";
            last;
        }
    }

    die <<EOD if not defined $dirlist;
App-Fetchware-Util: Failed to download the specifed URL [$url] or path
[$opts{PATH}] using the included hostname in the url you specifed or any
mirrors. The mirrors are [@{[config('mirror')]}]. And the urls
that fetchware tried to download were [@urls].
EOD

    return $dirlist;
}



sub no_mirror_download_dirlist {
    my $url = shift;

    my $dirlist;
    if ($url =~ m!^ftp://.*$!) {
        $dirlist = ftp_download_dirlist($url);
    } elsif ($url =~ m!^http://.*$!) {
        $dirlist = http_download_dirlist($url);
    } elsif ($url =~ m!^file://.*$!) {
      $dirlist = file_download_dirlist($url);
    } else {
        die <<EOD;
App-Fetchware: run-time syntax error: the url parameter your provided in
your call to download_dirlist() [$url] does not have a supported URL scheme (the
http:// or ftp:// part). The only supported download types, schemes, are FTP and

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

            # and pasting or insane nested ifs.
            goto PATHERROR;
        }
    # ...then it's an error.
    } else {
        PATHERROR: die <<EOD;
App-Fetchware-Util: You can only specify either PATH or URL never both. Only
specify one or the other when you call download_file().
EOD
    }
    # Ensure the user has specified a mirror, because otherwise download_file()
    # will try to just download a path, and that's not going to work.
    if (not config('mirror') and exists $opts{PATH}
        and
    # True if lookup_url is a file and if lookup_url is undef.
    defined config('lookup_url') ?
    config('lookup_url') =~ m!^file://! ? 1 : 0
    : 1
    ) {
        die <<EOD ;
App-Fetchware-Util: You only called download_file() with just a PATH parameter,
but also failed to specify any mirrors in your configuration. Without any
defined mirrors download_file() cannot determine from what host to download your
file. Please specify a mirror and try again.
EOD
    }

    # Set up our list of urls that we'll try to download the specified PATH or
    # URL from.
    my @urls = config('mirror') if defined config('mirror');
    # If we're called with a PATH option and the lookup_url is for a local file,
    # then we should just convert from a PATH into a $url.
    if (exists $opts{PATH}
        and
        # Is lookup_url not a file://, true for undef and any other scheme.
        defined config('lookup_url') ?
        config('lookup_url') =~ m!^file://! ? 1 : 0
        : 0
    ) {
        $url = "file://$opts{PATH}";
        delete $opts{PATH};
    # Otherwise, we should add lookup_url's hostname to the list of mirrors, but
    # be sure to push it onto @urls so that it is used last.
    #
    # But only if lookup_url is defined.
    } elsif (defined config('lookup_url')) {
        my ($scheme, $auth, undef, undef, undef) =
            uri_split(config('lookup_url'));
        push @urls, uri_join($scheme, $auth, undef, undef, undef);
    }

    if (exists $opts{PATH}
        and defined $opts{PATH}
        and $opts{PATH}) {
        # The PATH option means that $url is not a full blown URL, but just a
        # path without a hostname or scheme portion.
        # Therefore, we append $url, because the PATH option means it's actually
        # just a path, so we append it to each @url.
        for my $mirror_url (@urls) {
            # If the $mirror_url has no path...
            my ($scheme, $auth, $path, $query, $frag) =
                uri_split($mirror_url);
            # Skip messing with the path if $path eq $opts{PATH}, which means the
            # current $mirror_url is $url, so we shouldn't add its own path to
            # itself--we should skip it instead.
            next if $path eq $opts{PATH};
            if ($path eq '') {
                #...then append $url's path.
                ###BUGALERT## As shown before I was using URI's much nicer
                #interface, but it was deleting the path instead of replacing
                #the path! I tried reproducing this with a small test file, but
                #it worked just fine in the small test file. So, it must be some
                #really weird bug to fail here, but work in a smaller test file.
                #I don't know try replacing all of the URI::Split calls with the
                #equivelent URI->path() calls, and you'll get the weird bug.
                #$mirror_url->path($opts{PATH});
                ###Add an unless ($opts{PATH} eq '')
                $mirror_url =
                    uri_join($scheme, $auth, $opts{PATH}, $query, $frag);
            # But if the $mirror_url does have a path...
            } else {
                #...Then keep the mirrors path intact.
                #
                # Because if you specify a path when you define that mirror
                # chances are you did it, because that mirror stores it in a
                # different directory. For example Apache is /apache on some
                # mirrors, but apache.hostname on other mirrors.
                #
                #Except add $path's basename, because otherwise we'll ask
                #for a dirlisting or try to download a directory as a file.
                unless ($path =~ m!/$!) {
                    $mirror_url = 
                        uri_join($scheme, $auth, $path . '/'
                            . file($opts{PATH})->basename(), $query, $frag);
                # Skip adding a '/' if ones already there at the end.
                } else {
                    $mirror_url = 
                        uri_join($scheme, $auth, $path
                            . file($opts{PATH})->basename(), $query, $frag);
                }
            }
        }
    } elsif (defined $url
        and $url) {
        # Add $url to @urls since it too has a hostname. And use unshift
        # to put it in the first position instead of last if you were to use
        # push.
        unshift @urls, $url;

        # I must parse out the path portion of the specified URL, because this
        # path portion will be appended to the mirrors you have specified.
        my $url_path = ( uri_split($url) )[2];
        for my $mirror_url (@urls) {
            # If the $mirror_url has no path...
            my ($scheme, $auth, $path, $query, $frag) =
                uri_split($mirror_url);
            # Skip messing with the path if $path eq $url_path, which means the
            # current $mirror_url is $url, so we shouldn't add its own path to
            # itself--we should skip it instead.
            next if $path eq $url_path;
            if ($path eq '') {
                #...then append $url's path.
                ###BUGALERT## As shown before I was using URI's much nicer
                #interface, but it was deleting the path instead of replacing
                #the path! I tried reproducing this with a small test file, but
                #it worked just fine in the small test file. So, it must be some
                #really weird bug to fail here, but work in a smaller test file.
                #I don't know try replacing all of the URI::Split calls with the
                #equivelent URI->path() calls, and you'll get the weird bug.
                #$mirror_url->path($url_path);
                ###Add an unless ($url_path eq '')
                $mirror_url =
                    uri_join($scheme, $auth, $url_path, $query, $frag);
            # But if the $mirror_url does have a path...
            } else {
                #...Then keep the mirrors path intact.
                #
                # Because if you specify a path when you define that mirror
                # chances are you did it, because that mirror stores it in a
                # different directory. For example Apache is /apache on some
                # mirrors, but apache.hostname on other mirrors.
                #
                #Except add $path's basename, because otherwise we'll ask
                #for a dirlisting or try to download a directory as a file.
                unless ($path =~ m!/$!) {
                    $mirror_url = 
                        uri_join($scheme, $auth, $path . '/'
                            . file($url_path)->basename(), $query, $frag);
                # Skip adding a '/' if ones already there at the end.
                } else {
                    $mirror_url = 
                        uri_join($scheme, $auth, $path
                            . file($url_path)->basename(), $query, $frag);
                }
            }
        }
    }

    my $filename;

    for my $mirror_url (@urls) {
        eval {
            msg "Attempting to download [$mirror_url].";
            # Try the mirror_url directly without trying any mirrors.
            $filename = no_mirror_download_file($mirror_url);
        };
        if ($@) {
            msg "File download attempt failed! Error was[";
            print $@;
            msg "].";
        }

        # Skip the rest of the @urls after we successfully download the $url.
        if (defined $filename) {
            msg "Successfully downloaded the file [$mirror_url].";
            last;
        }
    }

    die <<EOD if not defined $filename;
App-Fetchware-Util: Failed to download the specifed URL [$url] or path
[$opts{PATH}] using the included hostname in the url you specifed or any
mirrors. The mirrors are [@{[config('mirror')]}]. And the urls
that fetchware tried to download were [@{[@urls]}].
EOD

    return $filename;
}



sub no_mirror_download_file {
    my $url = shift;

    my $filename;
    if ($url =~ m!^ftp://!) {
        $filename = download_ftp_url($url);
    } elsif ($url =~ m!^http://!) {
        $filename = download_http_url($url);
    } elsif ($url =~ m!^file://!) {
        $filename = download_file_url($url);   
    } else {
        die <<EOD;
App-Fetchware: run-time syntax error: the url parameter your provided in
your call to download_file() [$url] does not have a supported URL scheme (the
http:// or ftp:// part). The only supported download types, schemes, are FTP and
HTTP. See perldoc App::Fetchware.
EOD
    }

    return $filename;
}



( run in 1.075 second using v1.01-cache-2.11-cpan-b16cb0d3907 )