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