#! /bin/sh # cvsapply version 0.3 # Written by Gary V. Vaughan # Copyright 2001 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, a copy can be downloaded from # http://www.gnu.org/copyleft/gpl.html, or by writing to the Free # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA. # This script helps to generate a patch suitable for posting newsnet # while committing a change to the cvs repository. Typically you # might want to generate, commit and post a patch with a numerical # id: # cvsapply -z3 -i -m address@hidden -p fix-foo # # The `--id' option will use the number in the named file (if given) or # .patch_number in the current directory (by default) to determine the # ordinal number of the id'ed patch being generated. The number in # that file will be incremented after a patch has been successfully # generated. # # Similarly the `--rcfile' option will use the named file (if given) # or .cvsapplyrc in the current directory (by default) to set options. # The file should contain additional command line options, which will # be substituted into command line instead of the -r option that # references them. # usage: cvsapply [-v] [-h] [-1] [-b] [-c] [-f] [-n] [-q] [-r [file]] [-z N] # [-p patch-name] [-i [file]] [-m mail-addr] [--] [file|dir ...] # -1 extract the first ChangeLog entry for -c # -b --body send the patch in the body of the mail # -c --commit commit generated patch to repository # --fast alias for `-f -1' # -f --force omit the up-to-date check for -c # -i [FILE] --id[=FILE] use `N-$LOGNAME' patch id with -p # -l --local don't descend into subdirectories # -m ADDR --mail=ADDR recipient address for patch notification # -n --dry-run don't send mail or commit (if *after* -c) # -p NAME --patch=NAME save the patch in file NAME # -q --quiet run in silent mode # -r [FILE] --rcfile[=FILE] read default option from FILE [./.cvsapplyrc] # -v --verbose run in verbose mode # -zN --compress=N set compression level (0-9, 0=none, 9=max) # --version print version information # -h,-? --help print short or long help message me=cvsapply : ${CVS=cvs} dryrun=false mail=mutt mail_flags=-b clcommit=: commitopt= diffopt= cvsopt= to_addr="address@hidden" id_file= rc_file= save_file= tmp_file="${TMPDIR-/tmp}/$me-$$.patch" rm -f "$tmp_file" trap 'rm -f "$tmp_file"; exit 1' 1 2 15 die=: verbose=false copts_seen=false while test $# -gt 0; do case $1 in -1) commitopt="$commitopt -1" copts_seen=: shift ;; -b|--body) mail_flags=-i shift ;; -c|--commit) clcommit=clcommit shift ;; --debug) set -x shift ;; -i|--id) id_file="./.patch_number" if test $# -gt 1; then case $2 in -*) ;; *) id_file="$2" shift ;; esac fi shift ;; --fast) shift set -- -f -1 ${1+"$@"} ;; -f|--force) commitopt="$commitopt -f" copts_seen=: shift ;; -l|--local) diffopt="$diffopt -l" commitopt="$commitopt -l" shift ;; -m|--mail) if test $# = 1; then echo "$me: missing argument for $1" >&2 die=exit break fi shift to_addr="$1" shift ;; -n|--dryrun) dryrun=true clcommit=: mail=: shift ;; -p|--patch) if test $# = 1; then echo "$me: missing argument for $1" >&2 die=exit break fi shift save_file="$1" shift ;; -q|--quiet) cvsopt="$cvsopt -q" shift ;; -r|--rcfile) rc_file="./.cvsapplyrc" if test $# -gt 1; then case $2 in -*) ;; *) rc_file="$2" shift ;; esac fi shift if ! test -f "$rc_file"; then echo "$me: rcfile \`$rc_file' does not exist" >&2 die=exit break; fi eval set -- `cat $rc_file` \${1+"\$@"} ;; -v|--verbose) verbose=: shift ;; -z|--compress) if test $# = 1; then echo "$me: missing argument for $1" >&2 die=exit break fi shift case $1 in [0-9]) : ;; *) echo "$me: invalid argument for $1" >&2 die=exit break ;; esac cvsopt="$cvsopt -z$1" shift ;; -i*|-m*|-p*|-r*|-z*) opt=`echo "$1" | sed '1s/^\(..\).*$/\1/;q'` arg=`echo "$1" | sed '1s/^-[a-zA-Z0-9]//'` shift set -- "$opt" "$arg" ${1+"$@"} ;; -1*|-b*|-c*|-f*|-l*|-n*|-q*|-v*) opt=`echo "$1" | sed '1s/^\(..\).*$/\1/;q'` rest=`echo "$1" | sed '1s/^..\(.*\)$/-\1/;q'` shift set -- "$opt" "$rest" ${1+"$@"} ;; --compress=*|-id=*|--mail=*|--patch=*|--rcfile=*) opt=`echo "$1" | sed '1s/^\(--[^=]*\)=.*/\1/;q'` arg=`echo "$1" | sed '1s/^--[^=]*=//'` shift set -- "$opt" "$arg" ${1+"$@"} ;; --version) sed '/^# '$me' version /,/# warranty; / { s/^# //; p; }; d' < $0 exit 0 ;; -\?|-h) sed '/^# usage:/,/# -h/ { s/^# //; p; }; d' < $0 && echo echo "run \`$me --help | ${PAGER-more}' for full usage" exit 0 ;; --help) sed '/^# '$me' version /,/^[^#]/ { /^[^#]/ d; s/^# //; p; }; d' < $0 exit 0 ;; --) shift break ;; -*) echo "$name: invalid flag $1" >&2 break ;; *) break ;; esac done if test -n "$id_file" -o "$mail_flags" = -b && test -z "$save_file"; then echo "$me: \`-p' must be supplied if \`-i' or \`-b' are used" >&2 die=exit fi if $copts_seen && test "$clcommit" = ":"; then echo "$me: \`-c' must be supplied if \`-f' or \`-1' are used" >&2 die=exit fi if test -n "$id_file"; then test -s "$id_file" || echo 0 > "$id_file" ord=`expr \`cat "$id_file"\` + 1` || die=exit fi # Bail if the options were screwed $die 1 # Otherwise start the process... patch_file="${save_file-$tmp_file}" if test -n "$id_file"; then case $patch_file in */*|*\\*) patch_dir=`echo "$patch_file" | sed 's,/[^/]*$,,'` patch_file=`echo "$patch_file" | sed 's,^.*/,,g'` patch_file="$patch_dir/$ord-${LOGNAME-`logname`}-$patch_file" ;; *) patch_file="$ord-${LOGNAME-`logname`}-$patch_file" ;; esac case $patch_file in *.patch|*.diff) ;; *) patch_file="$patch_file.patch" ;; esac $dryrun || echo "$ord" > "$id_file" fi # Extract a patch file from cvs $verbose && echo "$me: cvs ${cvsopt} diff ${diffopt} -u" ${1+"$@"} >&2 cvs ${cvsopt} diff ${diffopt} -u ${1-"$@"} | sed '/^\? /,/^Index: /{ /^Index: /p; d; }' | fixpatch | clcleanup > "$patch_file" $verbose && echo "$me: generated $patch_file" >&2 # Commit those same changes if required $verbose && echo "$me: $clcommit $cvsopt $commitopt" ${1+"$@"} >&2 ${clcommit} ${cvsopt} ${commitopt} ${1+"$@"} # Send a mail notification if required ${mail} -s "FYI: $patch_file" $mail_flags "$patch_file" "$to_addr" rm -f "$tmp_file" exit 0