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