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