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