# cpan-upload - upload one or more file to CPAN (via PAUSE)
#
# $Id: cpan-upload,v 2.2 2002/07/02 21:44:10 neilb Exp $
#
use perl5:AppConfig::Std;
use perl5:Net::FTP;
use perl5:HTTP::Request::Common;
use perl5:LWP::UserAgent;
use perl5:HTTP::Status;
use perl5:File::Basename;
#-----------------------------------------------------------------------
# Configuration constants and globals
#-----------------------------------------------------------------------
my $PROGRAM;
my $SITE = 'pause.perl.org';
my $UPLOAD_DIR = 'incoming';
my $PAUSE_ADD_URI = 'http://p...content-available-to-author-only...l.org/pause/authenquery';
my $config;
my @uploaded_files;
our &POST := HTTP::Request::Common.can('POST');
our &basename := File::Basename.can('basename');
#-----------------------------------------------------------------------
# MAIN BODY
#-----------------------------------------------------------------------
my $VERSION = "Pugs $?PUGS_VERSION";
initialise();
@uploaded_files = ftp_upload_files(@*ARGS);
pause_add_files(@uploaded_files) if @uploaded_files > 0;
_verbose(int(@*ARGS), int(@*ARGS) == 1 ?? " file " !! " files ",
"uploaded successfully.\n");
#=======================================================================
#
# initialise()
#
# Create AppConfig instance, parse config file if there is one,
# and command-line options.
#
#=======================================================================
sub initialise () {
my $config_file;
my $HOME;
my $password;
($PROGRAM = $*PROGRAM_NAME) ~~ s:P5[^.*/] = '';
#-------------------------------------------------------------------
# Create an AppConfig::Std object, and define our interface
# The EXPAND flag on password tells AppConfig not to try and
# expand any embedded variables - eg if you have a $ sign
# in your password.
#-------------------------------------------------------------------
$HOME = %*ENV<HOME>;
$config_file = "$HOME/.pause";
$config = eval(q!
my $config = AppConfig::Std->new();
$config->define('user');
$config->define('directory', {ARGCOUNT => 1, ALIAS => 'dir'});
$config->define('password', { EXPAND => 0 });
$config->define('mailto');
$config->define('ftp_gateway');
$config->define('ftp_proxy');
$config->define('http_proxy');
$config->define('non_interactive', { ALIAS => 'ni', ARGCOUNT => 0 });
$config;
!, :lang<perl5>);
#-------------------------------------------------------------------
# Read the user's config file, if they have one,
# then parse the command-line.
#-------------------------------------------------------------------
if ($config_file ~~ :f)
{
$config.
file($config_file
) || exit 1; }
$config.args(\@*ARGS)
|| die "run \"$PROGRAM -help\" to see valid options\n";
#-------------------------------------------------------------------
# Check we have the information we need
#-------------------------------------------------------------------
die "No files specified for upload\n" unless @*ARGS > 0;
die "No email address (mailto) specified\n" unless $config.mailto;
die "No PAUSE user specified\n" unless $config.user;
$config.verbose(1) if $config.debug && !$config.verbose;
#-------------------------------------------------------------------
# Display banner at the start of the run
#-------------------------------------------------------------------
_verbose("$PROGRAM v$VERSION\n");
}
#=======================================================================
#
# ftp_upload_files()
#
# upload the one or more files to PAUSE ftp server.
# return a list of the files that were successfully uploaded.
#
#=======================================================================
sub ftp_upload_files (*@files) {
my @uploaded = (); # list of files actually uploaded
my $ftp; # Net::FTP instance
my @new_args; # arg list to pass to constructor
my ($user, $password); # user and password for login method
my $file;
_verbose("Using FTP to upload files to PAUSE\n");
#-------------------------------------------------------------------
# Make the connection to the PAUSE ftp server:
# First we determine how we're going to make the connection ...
#-------------------------------------------------------------------
if $config.ftp_gateway {
_debug(" establishing connection via an FTP gateway\n");
@new_args = ($config.ftp_gateway);
($user, $password) = ("ftp\@$SITE", $config.mailto);
}
else {
($user, $password) = ('ftp', $config.mailto);
@new_args = ($SITE);
if $config.ftp_proxy {
_debug(" establishing connection via proxy",
$config.ftp_proxy, "\n");
push(@new_args, Firewall => $config.ftp_proxy);
}
else {
_debug(" establishing connection\n");
}
}
#-------------------------------------------------------------------
# ... and then we actually make the connection and log in
#-------------------------------------------------------------------
$ftp = Net::FTP.new([,] @new_args);
if (!$ftp) {
die "failed to connect to remote server: $!\n";
}
if (!$ftp.login($user, $password)) {
$ftp.quit();
die " failed to login as user 'ftp', password $password - ",
$ftp.message(), "[", $ftp.code(), "]\n";
}
#-------------------------------------------------------------------
# Change to the right directory, and set binary mode
#-------------------------------------------------------------------
_debug(" changing to \"$UPLOAD_DIR\" directory...\n");
if (!$ftp.cwd($UPLOAD_DIR))
{
$ftp.quit();
die "failed to change directory to $UPLOAD_DIR!\n";
}
_debug(" setting binary mode.\n");
unless $ftp.binary() {
$ftp.quit();
die " failed to change type to 'binary' - ", $ftp.message(),
"[", $ftp.code(), "]\n";
}
#-------------------------------------------------------------------
# Put the file(s)
#-------------------------------------------------------------------
for @files -> $file {
_verbose(" uploading file \"$file\"\n");
if $ftp.put($file) {
push(@uploaded, $file);
}
else {
warn "failed to upload $file - ", $ftp.message(), "\n";
if (@files > 0 and !$config.non_interactive) {
my $continue;
repeat {
print "Do you want to continue? [y] ";
$continue = $*IN.get;
$continue = 'y' if $continue ~~ m:P5/^$/;
} while $continue !~~ m:P5/^[ynYN]/;
exit(0) if $continue ~~ m
:P5
/^[nN
]/; }
}
}
#-------------------------------------------------------------------
# Close the connection with the server.
#-------------------------------------------------------------------
_debug(" closing connection with FTP server\n");
$ftp.quit;
return @uploaded;
}
#=======================================================================
#
# pause_add_files()
#
# make an HTTP request to the add_uri form
#
#=======================================================================
sub pause_add_files (*@files) {
my $file;
my $basename;
my $request;
my $response;
my $agent;
my $argref;
_verbose("registering upload with PAUSE web server\n");
#-------------------------------------------------------------------
# Create the agent we'll use to make the web requests
#-------------------------------------------------------------------
_debug(" creating instance of LWP::UserAgent\n");
$agent = LWP::UserAgent.new() orelse die "Failed to create UserAgent: $!\n";
$agent.agent("$PROGRAM/$VERSION");
$agent.from($config.mailto);
if (defined $config.http_proxy)
{
$agent.proxy(['http'], $config.http_proxy);
}
#-------------------------------------------------------------------
# Post an upload message to the PAUSE web site for each file
#-------------------------------------------------------------------
for @files -> $file {
$basename = basename($file);
#---------------------------------------------------------------
# Create the request to add the file
#---------------------------------------------------------------
$argref = {
'HIDDENNAME' , "$config.user()",
'pause99_add_uri_upload' , "$basename",
'SUBMIT_pause99_add_uri_upload' , " Upload the checked file "
};
if ($config.directory)
{
$argref.{'pause99_add_uri_subdirtext'} = $config.directory;
}
$request = POST($PAUSE_ADD_URI, $argref);
$request.authorization_basic("$config.user()", "$config.password()");
_debug("----- REQUEST BEGIN -----\n",
$request.as_string(),
"----- REQUEST END -------\n");
#---------------------------------------------------------------
# Make the request to the PAUSE web server
#---------------------------------------------------------------
_verbose(" POSTing upload for $file\n");
$response = $agent.request($request);
#---------------------------------------------------------------
# So, how'd we do?
#---------------------------------------------------------------
if (not defined $response)
{
die "Request completely failed - we got undef back: $!\n";
}
if ($response.is_error)
{
if ($response.code == 404)
{
die "PAUSE's CGI for handling messages seems to have moved!\n",
"(HTTP response code of 404 from the PAUSE web server)\n",
"It used to be:\n\n\t", $PAUSE_ADD_URI, "\n\n",
"Please inform the maintainer of this script\n";
}
else
{
die "request failed\n Error code: ", $response.code,
"\n Message: ", $response.message, "\n";
}
}
else
{
_debug("Looks OK!\n",
"----- RESPONSE BEGIN -----\n",
$response.as_string(),
"----- RESPONSE END -------\n");
_verbose(" PAUSE add message sent ok [",
$response.code, "]\n");
}
}
}
#=======================================================================
#
# _verbose()
#
# displays the message strings passed if in verbose mode.
#
#=======================================================================
sub _verbose
{
return unless $config.verbose;
print join('', @_);
}
#=======================================================================
#
# _debug()
#
# displays the message strings passed if in debug mode.
#
#=======================================================================
sub _debug
{
return unless $config.debug;
print join('', @_);
}
__END__
#-----------------------------------------------------------------------