1#!/bin/sh 2# Sign files and upload them. 3 4scriptversion=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@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 31symlink_files= 32delete_files= 33delete_symlinks= 34collect_var= 35dbg= 36nl=' 37' 38 39usage="Usage: $0 [OPTION]... [CMD] FILE... [[CMD] FILE...] 40 41Sign all FILES, and process them at selected destinations according to CMD. 42<http://www.gnu.org/prep/maintain/html_node/Automated-FTP-Uploads.html> 43explains further. 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 --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 60If --symlink-regex is given without EXPR, then the link target name 61is created by replacing the version information with '-latest', e.g.: 62 63 foo-1.3.4.tar.gz -> foo-latest.tar.gz 64 65Recognized 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 75Options and commands are applied in order. If the file $conffile exists 76in the current working directory, its contents are prepended to the 77actual command line options. Use this to keep your defaults. Comments 78(#) and empty lines in $conffile are allowed. 79 80Examples: 811. Upload foobar-1.0.tar.gz to ftp.gnu.org: 82 gnupload --to ftp.gnu.org:foobar foobar-1.0.tar.gz 83 842. 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 873. 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 924. 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 975. 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 104gnupload uses the ncftpput program to do the transfers; if you don't 105happen to have an ncftp package installed, the ncftpput-ftp script in 106the build-aux/ directory of the gnulib package 107(http://savannah.gnu.org/projects/gnulib) may serve as a replacement. 108 109Send patches and bug reports to <bug-gnulib@gnu.org>." 110 111# Read local configuration file 112if 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 117fi 118 119while 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 187done 188 189dprint() 190{ 191 echo "Running $* ..." 192} 193 194if $dry_run; then 195 dbg=dprint 196fi 197 198if test -z "$to"; then 199 echo "$0: Missing destination sites" >&2 200 exit 1 201fi 202 203if 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 209fi 210 211if 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 216else 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 235fi 236 237# Make sure passphrase is not exported in the environment. 238unset 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. 246PATH=/empty echo -n "Enter GPG passphrase: " 247stty -echo 248read -r passphrase 249stty echo 250echo 251 252if 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 259fi 260 261 262# mkdirective DESTDIR BASE FILE STMT 263# Arguments: See upload, below 264mkdirective () 265{ 266 stmt="$4" 267 if test -n "$3"; then 268 stmt=" 269filename: $3$stmt" 270 fi 271 272 cat >${2}.directive<<EOF 273version: 1.1 274directory: $1 275comment: gnupload v. $scriptversion$stmt 276EOF 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 284mksymlink () 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. 302upload () 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 363stmt= 364if test -n "$symlink_files"; then 365 stmt="$stmt 366`mksymlink $symlink_files`" 367fi 368 369for file in $delete_files 370do 371 stmt="$stmt 372archive: $file" 373done 374 375for file in $delete_symlinks 376do 377 stmt="$stmt 378rmsymlink: $file" 379done 380 381if 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 387fi 388 389# Process actual uploads 390for dest in $to 391do 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 401symlink: $file $linkname 402symlink: $file.sig $linkname.sig" 403 fi 404 upload "$dest" "$destdir" "$file" "$file" "$stmt" "$files" 405 done 406done 407 408exit 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