Home | History | Annotate | Line # | Download | only in build-aux
gnupload revision 1.1.1.1
      1  1.1  christos #!/bin/sh
      2  1.1  christos # Sign files and upload them.
      3  1.1  christos 
      4  1.1  christos scriptversion=2012-01-15.15; # UTC
      5  1.1  christos 
      6  1.1  christos # Copyright (C) 2004-2012 Free Software Foundation, Inc.
      7  1.1  christos #
      8  1.1  christos # This program is free software; you can redistribute it and/or modify
      9  1.1  christos # it under the terms of the GNU General Public License as published by
     10  1.1  christos # the Free Software Foundation; either version 2, or (at your option)
     11  1.1  christos # any later version.
     12  1.1  christos #
     13  1.1  christos # This program is distributed in the hope that it will be useful,
     14  1.1  christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  1.1  christos # GNU General Public License for more details.
     17  1.1  christos #
     18  1.1  christos # You should have received a copy of the GNU General Public License
     19  1.1  christos # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     20  1.1  christos 
     21  1.1  christos # Originally written by Alexandre Duret-Lutz <adl (at] gnu.org>.
     22  1.1  christos # The master copy of this file is maintained in the gnulib Git repository.
     23  1.1  christos # Please send bug reports and feature requests to bug-gnulib (at] gnu.org.
     24  1.1  christos 
     25  1.1  christos set -e
     26  1.1  christos 
     27  1.1  christos GPG='gpg --batch --no-tty'
     28  1.1  christos conffile=.gnuploadrc
     29  1.1  christos to=
     30  1.1  christos dry_run=false
     31  1.1  christos symlink_files=
     32  1.1  christos delete_files=
     33  1.1  christos delete_symlinks=
     34  1.1  christos collect_var=
     35  1.1  christos dbg=
     36  1.1  christos nl='
     37  1.1  christos '
     38  1.1  christos 
     39  1.1  christos usage="Usage: $0 [OPTION]... [CMD] FILE... [[CMD] FILE...]
     40  1.1  christos 
     41  1.1  christos Sign all FILES, and process them at selected destinations according to CMD.
     42  1.1  christos <http://www.gnu.org/prep/maintain/html_node/Automated-FTP-Uploads.html>
     43  1.1  christos explains further.
     44  1.1  christos 
     45  1.1  christos Commands:
     46  1.1  christos   --delete                 delete FILES from destination
     47  1.1  christos   --symlink                create symbolic links
     48  1.1  christos   --rmsymlink              remove symbolic links
     49  1.1  christos   --                       treat the remaining arguments as files to upload
     50  1.1  christos 
     51  1.1  christos Options:
     52  1.1  christos   --help                   print this help text and exit
     53  1.1  christos   --to DEST                specify one destination for FILES
     54  1.1  christos                            (multiple --to options are allowed)
     55  1.1  christos   --user NAME              sign with key NAME
     56  1.1  christos   --symlink-regex[=EXPR]   use sed script EXPR to compute symbolic link names
     57  1.1  christos   --dry-run                do nothing, show what would have been done
     58  1.1  christos   --version                output version information and exit
     59  1.1  christos 
     60  1.1  christos If --symlink-regex is given without EXPR, then the link target name
     61  1.1  christos is created by replacing the version information with '-latest', e.g.:
     62  1.1  christos 
     63  1.1  christos   foo-1.3.4.tar.gz -> foo-latest.tar.gz
     64  1.1  christos 
     65  1.1  christos Recognized destinations are:
     66  1.1  christos   alpha.gnu.org:DIRECTORY
     67  1.1  christos   savannah.gnu.org:DIRECTORY
     68  1.1  christos   savannah.nongnu.org:DIRECTORY
     69  1.1  christos   ftp.gnu.org:DIRECTORY
     70  1.1  christos                            build directive files and upload files by FTP
     71  1.1  christos   download.gnu.org.ua:{alpha|ftp}/DIRECTORY
     72  1.1  christos                            build directive files and upload files by SFTP
     73  1.1  christos   [user@]host:DIRECTORY    upload files with scp
     74  1.1  christos 
     75  1.1  christos Options and commands are applied in order.  If the file $conffile exists
     76  1.1  christos in the current working directory, its contents are prepended to the
     77  1.1  christos actual command line options.  Use this to keep your defaults.  Comments
     78  1.1  christos (#) and empty lines in $conffile are allowed.
     79  1.1  christos 
     80  1.1  christos Examples:
     81  1.1  christos 1. Upload foobar-1.0.tar.gz to ftp.gnu.org:
     82  1.1  christos   gnupload --to ftp.gnu.org:foobar foobar-1.0.tar.gz
     83  1.1  christos 
     84  1.1  christos 2. Upload foobar-1.0.tar.gz and foobar-1.0.tar.xz to ftp.gnu.org:
     85  1.1  christos   gnupload --to ftp.gnu.org:foobar foobar-1.0.tar.gz foobar-1.0.tar.xz
     86  1.1  christos 
     87  1.1  christos 3. Same as above, and also create symbolic links to foobar-latest.tar.*:
     88  1.1  christos   gnupload --to ftp.gnu.org:foobar \\
     89  1.1  christos            --symlink-regex \\
     90  1.1  christos            foobar-1.0.tar.gz foobar-1.0.tar.xz
     91  1.1  christos 
     92  1.1  christos 4. Upload foobar-0.9.90.tar.gz to two sites:
     93  1.1  christos   gnupload --to alpha.gnu.org:foobar \\
     94  1.1  christos            --to sources.redhat.com:~ftp/pub/foobar \\
     95  1.1  christos            foobar-0.9.90.tar.gz
     96  1.1  christos 
     97  1.1  christos 5. Delete oopsbar-0.9.91.tar.gz and upload foobar-0.9.91.tar.gz
     98  1.1  christos    (the -- terminates the list of files to delete):
     99  1.1  christos   gnupload --to alpha.gnu.org:foobar \\
    100  1.1  christos            --to sources.redhat.com:~ftp/pub/foobar \\
    101  1.1  christos            --delete oopsbar-0.9.91.tar.gz \\
    102  1.1  christos            -- foobar-0.9.91.tar.gz
    103  1.1  christos 
    104  1.1  christos gnupload uses the ncftpput program to do the transfers; if you don't
    105  1.1  christos happen to have an ncftp package installed, the ncftpput-ftp script in
    106  1.1  christos the build-aux/ directory of the gnulib package
    107  1.1  christos (http://savannah.gnu.org/projects/gnulib) may serve as a replacement.
    108  1.1  christos 
    109  1.1  christos Send patches and bug reports to <bug-gnulib (at] gnu.org>."
    110  1.1  christos 
    111  1.1  christos # Read local configuration file
    112  1.1  christos if test -r "$conffile"; then
    113  1.1  christos   echo "$0: Reading configuration file $conffile"
    114  1.1  christos   conf=`sed 's/#.*$//;/^$/d' "$conffile" | tr "\015$nl" '  '`
    115  1.1  christos   eval set x "$conf \"\$@\""
    116  1.1  christos   shift
    117  1.1  christos fi
    118  1.1  christos 
    119  1.1  christos while test -n "$1"; do
    120  1.1  christos   case $1 in
    121  1.1  christos   -*)
    122  1.1  christos     collect_var=
    123  1.1  christos     case $1 in
    124  1.1  christos     --help)
    125  1.1  christos       echo "$usage"
    126  1.1  christos       exit $?
    127  1.1  christos       ;;
    128  1.1  christos     --to)
    129  1.1  christos       if test -z "$2"; then
    130  1.1  christos         echo "$0: Missing argument for --to" 1>&2
    131  1.1  christos         exit 1
    132  1.1  christos       else
    133  1.1  christos         to="$to $2"
    134  1.1  christos         shift
    135  1.1  christos       fi
    136  1.1  christos       ;;
    137  1.1  christos     --user)
    138  1.1  christos       if test -z "$2"; then
    139  1.1  christos         echo "$0: Missing argument for --user" 1>&2
    140  1.1  christos         exit 1
    141  1.1  christos       else
    142  1.1  christos         GPG="$GPG --local-user $2"
    143  1.1  christos         shift
    144  1.1  christos       fi
    145  1.1  christos       ;;
    146  1.1  christos     --delete)
    147  1.1  christos       collect_var=delete_files
    148  1.1  christos       ;;
    149  1.1  christos     --rmsymlink)
    150  1.1  christos       collect_var=delete_symlinks
    151  1.1  christos       ;;
    152  1.1  christos     --symlink-regex=*)
    153  1.1  christos       symlink_expr=`expr "$1" : '[^=]*=\(.*\)'`
    154  1.1  christos       ;;
    155  1.1  christos     --symlink-regex)
    156  1.1  christos       symlink_expr='s|-[0-9][0-9\.]*\(-[0-9][0-9]*\)\{0,1\}\.|-latest.|'
    157  1.1  christos       ;;
    158  1.1  christos     --symlink)
    159  1.1  christos       collect_var=symlink_files
    160  1.1  christos       ;;
    161  1.1  christos     --dry-run|-n)
    162  1.1  christos       dry_run=:
    163  1.1  christos       ;;
    164  1.1  christos     --version)
    165  1.1  christos       echo "gnupload $scriptversion"
    166  1.1  christos       exit $?
    167  1.1  christos       ;;
    168  1.1  christos     --)
    169  1.1  christos       shift
    170  1.1  christos       break
    171  1.1  christos       ;;
    172  1.1  christos     -*)
    173  1.1  christos       echo "$0: Unknown option '$1', try '$0 --help'" 1>&2
    174  1.1  christos       exit 1
    175  1.1  christos       ;;
    176  1.1  christos     esac
    177  1.1  christos     ;;
    178  1.1  christos   *)
    179  1.1  christos     if test -z "$collect_var"; then
    180  1.1  christos       break
    181  1.1  christos     else
    182  1.1  christos       eval "$collect_var=\"\$$collect_var $1\""
    183  1.1  christos     fi
    184  1.1  christos     ;;
    185  1.1  christos   esac
    186  1.1  christos   shift
    187  1.1  christos done
    188  1.1  christos 
    189  1.1  christos dprint()
    190  1.1  christos {
    191  1.1  christos   echo "Running $* ..."
    192  1.1  christos }
    193  1.1  christos 
    194  1.1  christos if $dry_run; then
    195  1.1  christos   dbg=dprint
    196  1.1  christos fi
    197  1.1  christos 
    198  1.1  christos if test -z "$to"; then
    199  1.1  christos   echo "$0: Missing destination sites" >&2
    200  1.1  christos   exit 1
    201  1.1  christos fi
    202  1.1  christos 
    203  1.1  christos if test -n "$symlink_files"; then
    204  1.1  christos   x=`echo "$symlink_files" | sed 's/[^ ]//g;s/  //g'`
    205  1.1  christos   if test -n "$x"; then
    206  1.1  christos     echo "$0: Odd number of symlink arguments" >&2
    207  1.1  christos     exit 1
    208  1.1  christos   fi
    209  1.1  christos fi
    210  1.1  christos 
    211  1.1  christos if test $# = 0; then
    212  1.1  christos   if test -z "${symlink_files}${delete_files}${delete_symlinks}"; then
    213  1.1  christos     echo "$0: No file to upload" 1>&2
    214  1.1  christos     exit 1
    215  1.1  christos   fi
    216  1.1  christos else
    217  1.1  christos   # Make sure all files exist.  We don't want to ask
    218  1.1  christos   # for the passphrase if the script will fail.
    219  1.1  christos   for file
    220  1.1  christos   do
    221  1.1  christos     if test ! -f $file; then
    222  1.1  christos       echo "$0: Cannot find '$file'" 1>&2
    223  1.1  christos       exit 1
    224  1.1  christos     elif test -n "$symlink_expr"; then
    225  1.1  christos       linkname=`echo $file | sed "$symlink_expr"`
    226  1.1  christos       if test -z "$linkname"; then
    227  1.1  christos         echo "$0: symlink expression produces empty results" >&2
    228  1.1  christos         exit 1
    229  1.1  christos       elif test "$linkname" = $file; then
    230  1.1  christos         echo "$0: symlink expression does not alter file name" >&2
    231  1.1  christos         exit 1
    232  1.1  christos       fi
    233  1.1  christos     fi
    234  1.1  christos   done
    235  1.1  christos fi
    236  1.1  christos 
    237  1.1  christos # Make sure passphrase is not exported in the environment.
    238  1.1  christos unset passphrase
    239  1.1  christos 
    240  1.1  christos # Reset PATH to be sure that echo is a built-in.  We will later use
    241  1.1  christos # 'echo $passphrase' to output the passphrase, so it is important that
    242  1.1  christos # it is a built-in (third-party programs tend to appear in 'ps'
    243  1.1  christos # listings with their arguments...).
    244  1.1  christos # Remember this script runs with 'set -e', so if echo is not built-in
    245  1.1  christos # it will exit now.
    246  1.1  christos PATH=/empty echo -n "Enter GPG passphrase: "
    247  1.1  christos stty -echo
    248  1.1  christos read -r passphrase
    249  1.1  christos stty echo
    250  1.1  christos echo
    251  1.1  christos 
    252  1.1  christos if test $# -ne 0; then
    253  1.1  christos   for file
    254  1.1  christos   do
    255  1.1  christos     echo "Signing $file ..."
    256  1.1  christos     rm -f $file.sig
    257  1.1  christos     echo "$passphrase" | $dbg $GPG --passphrase-fd 0 -ba -o $file.sig $file
    258  1.1  christos   done
    259  1.1  christos fi
    260  1.1  christos 
    261  1.1  christos 
    262  1.1  christos # mkdirective DESTDIR BASE FILE STMT
    263  1.1  christos # Arguments: See upload, below
    264  1.1  christos mkdirective ()
    265  1.1  christos {
    266  1.1  christos   stmt="$4"
    267  1.1  christos   if test -n "$3"; then
    268  1.1  christos     stmt="
    269  1.1  christos filename: $3$stmt"
    270  1.1  christos   fi
    271  1.1  christos 
    272  1.1  christos   cat >${2}.directive<<EOF
    273  1.1  christos version: 1.1
    274  1.1  christos directory: $1
    275  1.1  christos comment: gnupload v. $scriptversion$stmt
    276  1.1  christos EOF
    277  1.1  christos   if $dry_run; then
    278  1.1  christos     echo "File ${2}.directive:"
    279  1.1  christos     cat ${2}.directive
    280  1.1  christos     echo "File ${2}.directive:" | sed 's/./-/g'
    281  1.1  christos   fi
    282  1.1  christos }
    283  1.1  christos 
    284  1.1  christos mksymlink ()
    285  1.1  christos {
    286  1.1  christos   while test $# -ne 0
    287  1.1  christos   do
    288  1.1  christos     echo "symlink: $1 $2"
    289  1.1  christos     shift
    290  1.1  christos     shift
    291  1.1  christos   done
    292  1.1  christos }
    293  1.1  christos 
    294  1.1  christos # upload DEST DESTDIR BASE FILE STMT FILES
    295  1.1  christos # Arguments:
    296  1.1  christos #  DEST     Destination site;
    297  1.1  christos #  DESTDIR  Destination directory;
    298  1.1  christos #  BASE     Base name for the directive file;
    299  1.1  christos #  FILE     Name of the file to distribute (may be empty);
    300  1.1  christos #  STMT     Additional statements for the directive file;
    301  1.1  christos #  FILES    List of files to upload.
    302  1.1  christos upload ()
    303  1.1  christos {
    304  1.1  christos   dest=$1
    305  1.1  christos   destdir=$2
    306  1.1  christos   base=$3
    307  1.1  christos   file=$4
    308  1.1  christos   stmt=$5
    309  1.1  christos   files=$6
    310  1.1  christos 
    311  1.1  christos   rm -f $base.directive $base.directive.asc
    312  1.1  christos   case $dest in
    313  1.1  christos     alpha.gnu.org:*)
    314  1.1  christos       mkdirective "$destdir" "$base" "$file" "$stmt"
    315  1.1  christos       echo "$passphrase" | $dbg $GPG --passphrase-fd 0 --clearsign $base.directive
    316  1.1  christos       $dbg ncftpput ftp-upload.gnu.org /incoming/alpha $files $base.directive.asc
    317  1.1  christos       ;;
    318  1.1  christos     ftp.gnu.org:*)
    319  1.1  christos       mkdirective "$destdir" "$base" "$file" "$stmt"
    320  1.1  christos       echo "$passphrase" | $dbg $GPG --passphrase-fd 0 --clearsign $base.directive
    321  1.1  christos       $dbg ncftpput ftp-upload.gnu.org /incoming/ftp $files $base.directive.asc
    322  1.1  christos       ;;
    323  1.1  christos     savannah.gnu.org:*)
    324  1.1  christos       if test -z "$files"; then
    325  1.1  christos         echo "$0: warning: standalone directives not applicable for $dest" >&2
    326  1.1  christos       fi
    327  1.1  christos       $dbg ncftpput savannah.gnu.org /incoming/savannah/$destdir $files
    328  1.1  christos       ;;
    329  1.1  christos     savannah.nongnu.org:*)
    330  1.1  christos       if test -z "$files"; then
    331  1.1  christos         echo "$0: warning: standalone directives not applicable for $dest" >&2
    332  1.1  christos       fi
    333  1.1  christos       $dbg ncftpput savannah.nongnu.org /incoming/savannah/$destdir $files
    334  1.1  christos       ;;
    335  1.1  christos     download.gnu.org.ua:alpha/*|download.gnu.org.ua:ftp/*)
    336  1.1  christos       destdir_p1=`echo "$destdir" | sed 's,^[^/]*/,,'`
    337  1.1  christos       destdir_topdir=`echo "$destdir" | sed 's,/.*,,'`
    338  1.1  christos       mkdirective "$destdir_p1" "$base" "$file" "$stmt"
    339  1.1  christos       echo "$passphrase" | $dbg $GPG --passphrase-fd 0 --clearsign $base.directive
    340  1.1  christos       for f in $files $base.directive.asc
    341  1.1  christos       do
    342  1.1  christos         echo put $f
    343  1.1  christos       done | $dbg sftp -b - puszcza.gnu.org.ua:/incoming/$destdir_topdir
    344  1.1  christos       ;;
    345  1.1  christos     /*)
    346  1.1  christos       dest_host=`echo "$dest" | sed 's,:.*,,'`
    347  1.1  christos       mkdirective "$destdir" "$base" "$file" "$stmt"
    348  1.1  christos       echo "$passphrase" | $dbg $GPG --passphrase-fd 0 --clearsign $base.directive
    349  1.1  christos       $dbg cp $files $base.directive.asc $dest_host
    350  1.1  christos       ;;
    351  1.1  christos     *)
    352  1.1  christos       if test -z "$files"; then
    353  1.1  christos         echo "$0: warning: standalone directives not applicable for $dest" >&2
    354  1.1  christos       fi
    355  1.1  christos       $dbg scp $files $dest
    356  1.1  christos       ;;
    357  1.1  christos   esac
    358  1.1  christos   rm -f $base.directive $base.directive.asc
    359  1.1  christos }
    360  1.1  christos 
    361  1.1  christos #####
    362  1.1  christos # Process any standalone directives
    363  1.1  christos stmt=
    364  1.1  christos if test -n "$symlink_files"; then
    365  1.1  christos   stmt="$stmt
    366  1.1  christos `mksymlink $symlink_files`"
    367  1.1  christos fi
    368  1.1  christos 
    369  1.1  christos for file in $delete_files
    370  1.1  christos do
    371  1.1  christos   stmt="$stmt
    372  1.1  christos archive: $file"
    373  1.1  christos done
    374  1.1  christos 
    375  1.1  christos for file in $delete_symlinks
    376  1.1  christos do
    377  1.1  christos   stmt="$stmt
    378  1.1  christos rmsymlink: $file"
    379  1.1  christos done
    380  1.1  christos 
    381  1.1  christos if test -n "$stmt"; then
    382  1.1  christos   for dest in $to
    383  1.1  christos   do
    384  1.1  christos     destdir=`echo $dest | sed 's/[^:]*://'`
    385  1.1  christos     upload "$dest" "$destdir" "`hostname`-$$" "" "$stmt"
    386  1.1  christos   done
    387  1.1  christos fi
    388  1.1  christos 
    389  1.1  christos # Process actual uploads
    390  1.1  christos for dest in $to
    391  1.1  christos do
    392  1.1  christos   for file
    393  1.1  christos   do
    394  1.1  christos     echo "Uploading $file to $dest ..."
    395  1.1  christos     stmt=
    396  1.1  christos     files="$file $file.sig"
    397  1.1  christos     destdir=`echo $dest | sed 's/[^:]*://'`
    398  1.1  christos     if test -n "$symlink_expr"; then
    399  1.1  christos       linkname=`echo $file | sed "$symlink_expr"`
    400  1.1  christos       stmt="$stmt
    401  1.1  christos symlink: $file $linkname
    402  1.1  christos symlink: $file.sig $linkname.sig"
    403  1.1  christos     fi
    404  1.1  christos     upload "$dest" "$destdir" "$file" "$file" "$stmt" "$files"
    405  1.1  christos   done
    406  1.1  christos done
    407  1.1  christos 
    408  1.1  christos exit 0
    409  1.1  christos 
    410  1.1  christos # Local variables:
    411  1.1  christos # eval: (add-hook 'write-file-hooks 'time-stamp)
    412  1.1  christos # time-stamp-start: "scriptversion="
    413  1.1  christos # time-stamp-format: "%:y-%02m-%02d.%02H"
    414  1.1  christos # time-stamp-time-zone: "UTC"
    415  1.1  christos # time-stamp-end: "; # UTC"
    416  1.1  christos # End:
    417