——#!/apps/perl5/bin/perl -w
=head1 NAME
cpan-upload - upload one or more files to CPAN, using PAUSE
=head1 SYNOPSIS
cpan-upload [options] file1 .. fileN
=head1 DESCRIPTION
B<cpan-upload> is a script which automates the process of uploading
a file to CPAN using PAUSE, the Perl Authors Upload SErver.
Before using this script you must register with PAUSE,
to get a username and password.
If you are a regular uploader to PAUSE, you'll probably want to
create a C<.pause> configuration file. If not, you can probably
just use the command-line options, as described below.
If everything went OK, you'll get a mail message from the PAUSE monitor.
=head1 OPTIONS
=over 4
=item -user <string>
Your PAUSE username which was registered with PAUSE.
=item -password <string>
The password for your PAUSE username.
=item -ftp_firewall <host>
Specifies the name of the host which has your ftp firewall gateway,
if you're behind a firewall.
=item -http_proxy <URL>
Specifies the URL for a proxy to use when making HTTP requests.
=item -mailto <email>
Your email address, to include the HTTP request header.
This is also used as the password for the ftp upload to PAUSE.
=item -help
Displays a short help message.
=item -doc
Display the full documentation for B<orange>.
=item -verbose
Turns on verbose information as the script runs.
=item -debug
Turns on debugging information. Useful mainly for the developer,
it displays the HTTP request and response.
=item -version
Display the version number of the B<cpan-upload> script.
=back
=cut
use
strict;
use
App::Config;
use
Net::FTP;
use
LWP::UserAgent;
use
HTTP::Response;
use
HTTP::Status;
use
File::Basename;
use
Pod::Usage;
$VERSION
=
'1.3'
;
#-----------------------------------------------------------------------
# CONFIGURATION CONSTANTS
#-----------------------------------------------------------------------
my
$PROGRAM
=
'CPAN Upload Script'
;
my
$SITE
=
'pause.kbx.de'
;
my
$UPLOAD_DIR
=
'incoming'
;
my
$agent
;
my
$config
;
my
$file
;
#-----------------------------------------------------------------------
# MAIN BODY
#-----------------------------------------------------------------------
initialise();
ftp_upload_files(
@ARGV
);
" Adding files via PAUSE web server...\n"
;
foreach
$file
(
@ARGV
)
{
pause_add_file(
$file
);
}
exit
0;
sub
initialise
{
my
$config_file
;
my
$HOME
;
#-------------------------------------------------------------------
# Turn off buffering on STDOUT
#-------------------------------------------------------------------
$| = 1;
#-------------------------------------------------------------------
# Create an App::Config object, and define our interface
#-------------------------------------------------------------------
$HOME
=
$ENV
{
'HOME'
} || (
getpwuid
($<))[7];
$config_file
=
"$HOME/.pause"
;
if
(-e
$config_file
&& ((
stat
(
$config_file
))[2] & 36) != 0)
{
die
"$PROGRAM: your config file $config_file is readable by others!\n"
;
}
$config
= new App::Config({
GLOBAL
=> {
CMDARG
=> 1,
ARGCOUNT
=> 1}});
$config
->define(
'user'
);
$config
->define(
'password'
, {
EXPAND
=> 0 });
$config
->define(
'mailto'
);
$config
->define(
'ftp_firewall'
);
$config
->define(
'http_proxy'
);
$config
->define(
'help'
, {
ARGCOUNT
=> 0 } );
$config
->define(
'doc'
, {
ARGCOUNT
=> 0 });
$config
->define(
'debug'
, {
ARGCOUNT
=> 0 } );
$config
->define(
'verbose'
, {
ARGCOUNT
=> 0 } );
$config
->define(
'version'
, {
ARGCOUNT
=> 0 } );
#-------------------------------------------------------------------
# Read the user's config file, if they have one,
# then parse the command-line.
#-------------------------------------------------------------------
if
(-f
$config_file
)
{
$config
->cfg_file(
$config_file
) ||
exit
1;
}
$config
->cmd_line(\
@ARGV
) ||
exit
1;
#-------------------------------------------------------------------
# Did they give one of the informational switches?
#-------------------------------------------------------------------
pod2usage(
verbose
=> 2,
exitval
=> 0)
if
$config
->doc();
pod2usage(
verbose
=> 1,
exitval
=> 0)
if
$config
->help();
show_version()
if
$config
->version;
#-------------------------------------------------------------------
# Check we have the information we need
#-------------------------------------------------------------------
die
"No email address (mailto) specified\n"
unless
$config
->mailto;
die
"No PAUSE user specified\n"
unless
$config
->user;
die
"No password specified\n"
unless
$config
->password;
#-------------------------------------------------------------------
# Display banner at the start of the run
#-------------------------------------------------------------------
"$PROGRAM v$VERSION\n"
;
}
#=======================================================================
# ftp_upload_files() - upload the one or more files to PAUSE ftp server
#=======================================================================
sub
ftp_upload_files
{
my
@files
=
@_
;
my
$ftp
;
my
$file
;
"\nFTP UPLOAD\n\n"
;
" opening FTP connection to $SITE . . ."
;
if
(
$config
->ftp_firewall)
{
verbose(
"\n\t(using firewall "
.
$config
->ftp_firewall.
")"
);
$ftp
= Net::FTP->new(
$SITE
,
'Firewall'
=>
$config
->ftp_firewall);
}
else
{
$ftp
= Net::FTP->new(
$SITE
);
}
if
(not
defined
$ftp
)
{
die
"Failed to create FTP object: $!\n"
;
}
$ftp
->login(
'ftp'
,
$config
->mailto);
"\n"
;
verbose(
" changing to \"$UPLOAD_DIR\" directory..."
);
$ftp
->cwd(
$UPLOAD_DIR
);
verbose(
" setting binary mode."
);
$ftp
->binary() ||
do
{
$ftp
->quit();
die
" failed to change type to 'binary'\n"
;
};
foreach
$file
(
@files
)
{
" uploading file \"$file\" . . ."
;
$ftp
->put(
$file
) ||
do
{
warn
"\n failed to upload.\n"
;
next
;
};
"\n"
;
}
$ftp
->quit;
"\n"
;
}
#=======================================================================
# pause_add_file() - make an HTTP request to the add_uri form
#=======================================================================
sub
pause_add_file
{
my
$file
=
shift
;
my
$basename
= basename(
$file
);
my
$request
;
my
$response
;
my
$formbody
;
#-------------------------------------------------------------------
# Create the agent we'll use to make the web requests
#-------------------------------------------------------------------
if
(not
defined
$agent
)
{
$agent
=
eval
{ new LWP::UserAgent };
die
"Failed to create UserAgent: $@\n"
if
($@ || (not
defined
$agent
));
$agent
->agent(
"CpanUpload/$VERSION"
);
$agent
->from(
$config
->mailto)
if
$config
->mailto;
if
(
defined
$config
->http_proxy)
{
$agent
->proxy([
'http'
],
$config
->http_proxy);
}
}
#-------------------------------------------------------------------
# Create the request to add the file
#-------------------------------------------------------------------
$request
= POST(PAUSE_ADD_URI, {
HIDDENNAME
=>
$config
->user(),
upload
=>
$basename
});
$request
->authorization_basic(
$config
->user,
$config
->password);
if
(
$config
->debug)
{
"----- REQUEST BEGIN -----\n"
;
$request
->as_string();
"----- REQUEST END -------\n"
;
}
#-------------------------------------------------------------------
# Make the request to the PAUSE web server
#-------------------------------------------------------------------
$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 == RC_NOT_FOUND)
{
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
{
if
(
$config
->debug)
{
"\nLooks OK!\n"
;
"----- RESPONSE BEGIN -----\n"
;
$response
->as_string();
"----- RESPONSE END -------\n"
;
}
else
{
"\tPAUSE add message sent ok ["
,
$response
->code,
"]\n"
;
}
}
}
#=======================================================================
# show_version() - show the version of script (in response to -version)
#=======================================================================
sub
show_version
{
STDERR
"$VERSION\n"
;
exit
0;
}
#=======================================================================
# verbose() - displays the message strings passed if in verbose mode
#=======================================================================
sub
verbose
{
return
unless
$config
->verbose;
join
(
"\n"
,
@_
),
"\n"
;
}
exit
0;
#-----------------------------------------------------------------------
=head1 CONFIGURATION FILE
You can provide the configuration information needed
via a .pause file in your home directory.
If you upload files at all regularly you will want to
set up one of these.
=over 4
=item user <username>
This is used to specify your PAUSE username.
This just saves you from typing it every time you run the script.
=item password <password>
This is used to specify your PAUSE password.
=item ftp_firewall <HOST>
Specifies the hostname of your ftp gateway used to get through
a firewall. For example:
ftp_proxy = ftp-gw
=item http_proxy <URL>
The URL for the proxy to use when making HTTP requests to the PAUSE
web server. For example:
http_proxy = http://proxy/
=item mailto <EMAIL>
Specifies the email address which is passed in the header of
the HTTP request, and as the password for the anonymous ftp upload.
You must provide this.
=back
The following is a sample .pause file:
# example .pause for user neilb
# the user is your registered PAUSE username
user NEILB
password thisisnotmyrealpassword
mailto = neilb@cre.canon.co.uk
ftp_firewall = ftp-gw
http_proxy = http://proxy.cre.canon.co.uk/
Note that your .pause must not be readable by others,
since it can contain your PAUSE password. The b<cpan-upload> script
refuses to run if your config file can be read by others.
=cut
=head1 SEE ALSO
=over 4
Our web page about Canon Research Europe and Perl.
=item App::Config
Andy Wardley's module for unifying command-line switches and
cofiguration files into the notion of configuration variables.
B<orange> requires version 1.07 of the module,
which is available from CPAN:
=item Net::FTP
Graham Barr's studly module for doing that crazy ftp thang.
=item libwww-perl5
The LWP distribution which provides the modules used by this script
to talk to the PAUSE web server. You can get the latest version from:
=item Pod::Usage
Brad Appleton's module for extracting usage information out
of a file's pod. This is used for the B<-doc> and B<-help> switches.
Available from CPAN:
=back
=head1 VERSION
$Id: cpan-upload,v 1.4 1998/07/24 11:19:00 neilb Exp $
=head1 AUTHOR
Neil Bowers E<lt>neilb@cre.canon.co.ukE<gt>
=head1 COPYRIGHT
Copyright (c) 1998 Canon Research Centre Europe. All rights reserved.
This script is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut