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