2 # Simple wrapper around svn featuring auto-ChangeLog entries and emailing.
4 # Copyright (C) 2006 Benoit Sigoure.
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 # Quick install: alias svn=path/to/svn-wrapper.sh -- that's all.
27 # This script is a wrapper around the svn command-line client for UNIX. It has
28 # been designed mainly to automagically generate GNU-style ChangeLog entries
29 # when committing and mail them along with a diff and an optional comment from
30 # the author to a list of persons or a mailing list. It has been made so that
31 # it's as much portable as possible and covers as many use-case as possible.
33 # HOWEVER, there will be bugs, there will be cases in which the script doesn't
34 # wrap properly the svn-cli, etc. In this case, you can try to mail me at
35 # <tsuna at lrde dot epita dot fr>. Include the revision of the svn-wrapper
36 # you're using, and full description of what's wrong etc. so I can reproduce
39 # If you feel like, you can try to fix/enhance the script yourself. It only
40 # requires some basic Shell-scripting skills. Knowing sed might help :)
46 # If you're simply looking for the usage, run svn-wrapper.sh help (or
47 # svn help if you aliased `svn' on svn-wrapper.sh) as usual.
49 # This script is (hopefully) portable, widely commented and self-contained. Do
50 # not hesitate to hack it. It might look rather long (because it does a lot of
51 # things :P) but you should be able to easily locate which part of the code
54 # The script begins by defining several functions. Then it really starts where
55 # the comment "# `main' starts here. #" is placed.
56 # Some svn commands are hooked (eg, svn st displays colors). Hooks and
57 # extra commands are defined in functions named svn_<command-name>.
63 # * Handle things such as svn ci --force foobar.
64 # * svn automerge + automatic fill in branches/README.branches.
65 # * Automatic proxy configuration depending on the IP in ifconfig?
66 # * Customizable behavior/colors via some ~/.<config>rc file (?)
67 # * Automatically recognize svn cp and svn mv instead of writting "New" and
68 # "Remove" in the template ChangeLog entry (hard). Pair the and new/remove
69 # to prepare a good ChangeLog entry (move to X, copy from X) [even harder].
70 # => svn info says whether an item was copied from a given *URL* or not.
74 # Default values (the user can export them to override them).
75 if [ x
"$SVN" = x
]; then
89 # Override the locale.
94 # Signal number for traps (using plain signal names is not portable and breaks
95 # on recent Debians that use ash as their default shell).
98 # Pitfall: some users might be tempted to export SVN=svn-wrapper.sh for some
99 # reason. This is just *wrong*. The following is an attempt to save them from
101 if [ x
`basename "$SVN"` = 'xsvn-wrapper.sh' ]; then
105 # This code comes (mostly) from Autoconf.
106 # The user is always right.
107 if test "${PATH_SEPARATOR+set}" != set; then
108 trap "echo SIGINT; rm -f '$TMPDIR/conf$$.sh'; exit 130" $SIGINT
109 echo "#! /bin/sh" >"$TMPDIR/conf$$.sh"
110 echo "exit 0" >>"$TMPDIR/conf$$.sh"
111 chmod +x
"$TMPDIR/conf$$.sh"
112 if (PATH
="/nonexistent;."; conf$$.sh
) >/dev
/null
2>&1; then
117 rm -f "$TMPDIR/conf$$.sh"
119 trap 'echo SIGINT; exit 130' $SIGINT
123 revision
=`sed '/^# $Id[:].*$/!d;
126 s/[^0-9]*\([0-9][0-9]*\).*/\1/' "$0"`
129 # The `main' really starts after the functions definitions.
137 red
='\e[0;31m'; lred
='\e[1;31m'
138 green
='\e[0;32m'; lgreen
='\e[1;32m'
139 yellow
='\e[0;33m'; lyellow
='\e[1;33m'
140 blue
='\e[0;34m'; lblue
='\e[1;34m'
141 purple
='\e[0;35m'; lpurple
='\e[1;35m'
142 cyan
='\e[0;36m'; lcyan
='\e[1;36m'
143 grey
='\e[0;37m'; lgrey
='\e[1;37m'
144 white
='\e[0;38m'; lwhite
='\e[1;38m'
152 yellow
=''; lyellow
=''
154 purple
=''; lpurple
=''
164 echo "svn-wrapper: ${lred}abort${std}: $@" \
165 |
sed '1!s/^[ ]*/ /' >&2
172 echo "svn-wrapper: ${lred}warning${std}: $@" \
173 |
sed '1!s/^[ ]*/ /' >&2
179 echo "svn-wrapper: ${lyellow}notice${std}: $@" \
180 |
sed '1!s/^[ ]*/ /' >&2
187 read answer ||
return 1
192 return 42 # should never happen...
196 # returns true if `yes' or `proceed', false if `new'.
197 # the answer is stored in $yesnoproceed_res which is /yes|new|proceed/
200 echo -n "$@ [(y)es/(p)roceed/(N)ew] "
201 read answer ||
return 1
203 y
* | Y
*) yesnoproceed_res
=yes; return 0;;
204 p
* | P
*) yesnoproceed_res
=proceed
; return 0;;
205 *) yesnoproceed_res
=new
; return 1;;
207 return 42 # should never happen...
213 warn
"cannot find the environment variable $1
214 You might consider using \`export $1 <FIXME>\`"
217 # get_unique_file_name file-name
218 get_unique_file_name
()
221 echo "$1" && return 0
224 while test -e "$gufn.$i"; do
230 # ensure_not_empty description value
233 ene_val
=`echo "$2" | tr -d ' \t\n'`
234 test x
"$ene_val" = x
&& abort
"$1: empty value"
237 # find_prog prog-name
238 # return true if prog-name is in the PATH
239 # echo the full path to prog-name on stdout.
240 # Based on a code from texi2dvi
247 test x
"$dir" = x
&& continue
248 # The basic test for an executable is `test -f $f && test -x $f'.
249 # (`test -x' is not enough, because it can also be true for directories.)
250 # We have to try this both for $1 and $1.exe.
252 # Note: On Cygwin and DJGPP, `test -x' also looks for .exe. On Cygwin,
253 # also `test -f' has this enhancement, bot not on DJGPP. (Both are
254 # design decisions, so there is little chance to make them consistent.)
255 # Thusly, it seems to be difficult to make use of these enhancements.
257 if test -f "$dir/$1" && test -x "$dir/$1"; then
260 elif test -f "$dir/$1.exe" && test -x "$dir/$1.exe"; then
268 # find_progs prog [progs...]
269 # Look in PATH for one of the programs given in argument.
270 # If none of the progs can be found, the string "exit 2" is "returned".
273 # This code comes mostly from Autoconf.
274 for fp_prog
in "$@"; do
275 fp_res
=`find_prog $fp_prog`
276 if [ $?
-eq 0 ]; then
285 test x
"$EDITOR" = xmissing
&& EDITOR
=`find_progs vim vi emacs nano`
286 test x
"$PAGER" = xmissing
&& PAGER
=`find_progs less more`
287 test x
"$AWK" = xmissing
&& AWK
=`find_progs gawk mawk nawk awk`
290 # return true if diffstat is in the PATH
293 if [ x
"$require_diffstat_cache" != x
]; then
294 return $require_diffstat_cache
296 if (echo | diffstat
) >/dev
/null
2>/dev
/null
; then :; else
297 warn
'diffstat is not installed on your system or not in your PATH.'
298 test -f /etc
/debian_version \
299 && notice
'you might want to `apt-get install diffstat`.'
300 require_diffstat_cache
=1
303 require_diffstat_cache
=0
308 # return 0 -> found sendmail
310 # 2 -> no mailer found
311 # The full path to the program found is echo'ed on stdout.
314 if [ x
"$require_mail_cache_rv" != x
]; then
315 echo "$require_mail_cache"
316 return $require_mail_cache_rv
319 PATH
="${PATH}${PATH_SEPARATOR}/sbin${PATH_SEPARATOR}/usr/sbin${PATH_SEPARATOR}/usr/libexec"
321 require_mail_cache
=`find_prog sendmail`
322 if [ $?
-eq 0 ] && [ x
"$require_mail_cache" != x
]; then
323 echo "$require_mail_cache"
324 require_mail_cache_rv
=0
329 require_mail_cache
=`find_prog mail`
330 if [ $?
-eq 0 ] && [ x
"$require_mail_cache" != x
]; then
331 echo "$require_mail_cache"
332 require_mail_cache_rv
=1
335 warn
'mail is not installed on your system or not in your PATH.'
336 test -f /etc
/debian_version \
337 && notice
'you might want to:
338 # apt-get install mailx
339 # dpkg-reconfigure exim'
340 require_mail_cache
=''
341 require_mail_cache_rv
=1
344 require_mail_cache
=''
345 require_mail_cache_rv
=42
349 # my_sendmail mail-file mail-subject mail-to [extra-headers]
350 # mail-to is a comma-separated list of email addresses.
351 # extra-headers is an optionnal argument and will be prepended at the
352 # beginning of the mail headers if the tool used to send mails supports it.
353 # The mail-file may also contain headers. They must be separated from the body
354 # of the mail by a blank line.
357 test -f "$1" || abort
"my_sendmail: Cannot find the mail file: $1"
358 test x
"$2" = x
&& warn
'my_sendmail: Empty subject.'
359 test x
"$3" = x
&& abort
'my_sendmail: No recipient specified.'
361 content_type
='Content-type: text/plain'
362 extra_headers
="X-Mailer: svn-wrapper v$version (r$revision)
364 Content-Transfer-Encoding: 7bit"
365 if test x
"$4" != x
; then
368 # Remove empty lines.
369 extra_headers
=`echo "$extra_headers" | sed '/^[ ]*$/d;s/^[ ]*//'`
372 # If we have a signature, add it.
373 if test -f ~
/.signature
; then
374 # But don't add it if it is already in the mail.
375 if grep -Fe "`cat ~/.signature`" "$1" >/dev
/null
; then :; else
376 echo '-- ' >>"$1" && cat ~
/.signature
>>"$1"
379 # VCS-compat: handle user option 'sign'.
380 if (grep '^sign: false' ~
/.vcs
) >/dev
/null
2>/dev
/null
; then :; else
381 ($GPG -h) >/dev
/null
2>/dev
/null
383 if [ -e ~
/.gnupg
] ||
[ -e ~
/.gpg
] ||
[ -e ~
/.pgp
] && [ $gpg_rv -lt 42 ]
385 if grep 'BEGIN PGP SIGNATURE' "$1" >/dev
/null
; then
386 notice
'message is already GPG-signed'
387 elif yesno
"Sign the mail using $GPG ?"; then
389 sed '1,/^$/d' "$1" >"$1.msg"
390 sed '1,/^$/!d' "$1" >"$1.hdr"
391 # Sign the message, keep only the PGP signature.
392 $GPG --clearsign <"$1.msg" >"$1.tmp" ||
{
393 rm -f "$1.msg" "$1.hdr" "$1.tmp"
394 abort
"\`$GPG' failed (r=$?)"
396 sed '/^--*BEGIN PGP SIGNATURE--*$/,/^--*END PGP SIGNATURE--*$/!d' \
399 boundary
="svn-wrapper-2-$RANDOM"
400 boundary
="$boundary$RANDOM"
401 # Prepend some stuff before the PGP signature.
404 content-type: application/pgp-signature; x-mac-type=70674453;
406 content-description: This is a digitally signed message part
407 content-disposition: inline; filename=PGP.sig
408 content-transfer-encoding: 7bit" |
cat - "$1.sig" >"$1.tmp"
409 mv -f "$1.tmp" "$1.sig"
411 # Append some stuff after the PGP signature.
413 --$boundary--" >>"$1.sig"
414 # Re-paste the headers before the signed body and prepend some stuff.
415 echo "This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
417 Content-Transfer-Encoding: 8bit
418 Content-Type: text/plain; charset=iso-8859-1; format=flowed
420 |
cat "$1.hdr" - "$1.msg" "$1.sig" >"$1.tmp" \
421 && mv -f "$1.tmp" "$1"
422 content_type
="Content-Type: multipart/signed;\
423 protocol=\"application/pgp-signature\"; micalg=pgp-sha1;\
424 boundary=\"$boundary\""
426 rm -f "$1.tmp" "$1.sig" "$1.msg" "$1.hdr"
427 extra_headers
="$extra_headers
428 X-Pgp-Agent: `$GPG --version | sed q`"
432 extra_headers
="$extra_headers
435 mailer
=`require_mail`
437 if [ $?
-ge 2 ] ||
[ x
"$mailer" = x
]; then
438 warn
'my_sendmail: No suitable mailer found.'
443 to
=`echo "$3" | sed 's/,//g'`
444 echo "$extra_headers" |
cat - "$1" |
$mailer $to;;
446 cat "$1" |
$mailer -s "$2" "$3";;
448 warn
'my_sendmail: Internal error.'; return 42;;
455 my_url
='http://www.lrde.epita.fr/~sigoure/svn-wrapper'
456 # You can use https if you feel paranoiac.
458 echo ">>> Fetching svn-wrapper.sh from $my_url/svn-wrapper.sh"
460 # --------------------- #
461 # Fetch the new version #
462 # --------------------- #
464 tmp_me
=`get_unique_file_name "$TMPDIR/svn-wrapper.sh"`
465 if (wget
--help) >/dev
/null
2>/dev
/null
; then
466 wget
--no-check-certificate "$my_url/svn-wrapper.sh" -O "$tmp_me"
469 curl
--help >/dev
/null
2>/dev
/null
470 if [ $?
-gt 42 ]; then
471 abort
'Cannot find wget or curl.
472 How can I download any update without them?'
475 curl
--insecure "$my_url/svn-wrapper.sh" >"$tmp_me"
479 || abort
"Cannot find the copy of myself I downloaded in $tmp_me"
481 # ---------------------------------------- #
482 # Compare versions and update if necessary #
483 # ---------------------------------------- #
486 tmp_ver
=`sed '/^# $Id[:].*$/!d;
489 s/[^0-9]*\([0-9][0-9]*\).*/\1/' "$tmp_me"`
490 test x
"$tmp_ver" = x
&& abort
"Cannot find the version of $tmp_me"
491 if [ "$my_ver" -lt "$tmp_ver" ]; then # There IS an update...
492 echo "An update is available, r$tmp_ver (your version is r$my_ver)"
495 if yesno
"Do you want to see the ChangeLog between r$my_ver and r$tmp_ver?"
497 my_chlog
=`get_unique_file_name "$TMPDIR/ChangeLog"`
499 wget
) wget
--no-check-certificate "$my_url/ChangeLog" -O "$my_chlog"
501 curl
) curl
--insecure "$my_url/ChangeLog" >"$my_chlog"
503 *) abort
'Should never be here.'
506 sed "/^r$my_ver/q" "$my_chlog" |
$PAGER
510 # Wanna see the diff?
511 if yesno
"Do you want to see the diff between r$my_ver and r$tmp_ver?"
513 (require_diffstat
&& diff -uw "$me" "$tmp_me" | diffstat
;
515 diff -uw "$me" "$tmp_me") |
$PAGER
519 if yesno
"Overwrite $me (r$my_ver) with $tmp_me (r$tmp_ver)?"; then
521 cp -p "$me" "$me.r$my_ver"
522 mv "$tmp_me" "$me" && exit 0
526 elif [ "$my_ver" -gt "$tmp_ver" ]; then
527 echo "Wow, you're more up to date than the master copy :)"
528 echo "Your version is r$my_ver and the master copy is r$tmp_ver."
529 if yesno
'Downgrade?'; then
531 mv "$tmp_me" "$me" && exit 0
534 echo "You're already up to date [r$my_ver] :)"
539 # get_svn_diff_and_diffstat [files to diff]
540 # Helper for svn_commit
541 get_svn_diff_and_diffstat
()
543 if [ x
"$SVN" = xgit
]; then
544 svn_diff
=`git diff --ignore-space-change --no-color -C HEAD`
545 svn_diff_stat
=`git diff --stat --ignore-space-change --no-color -C HEAD`
547 # Ignore white spaces. Can't svn diff -x -w: svn 1.4 only.
548 svn_diff
=`svn_diffw "$@"`
549 test x
"$svn_diff" = x
&& svn_diff
=`$SVN diff "$@"`
550 if require_diffstat
; then
551 svn_diff_stat
=`echo "$svn_diff" | diffstat`
553 svn_diff_stat
='diffstat not available'
558 # ------------------------------- #
559 # Hooks for standard SVN commands #
560 # ------------------------------- #
562 # svn_commit [args...]
563 # Here is how the commit process goes:
565 # First we look in the arguments passed to commit:
566 # If there are some files or paths, the user wants to commit these only. In
567 # this case, we must search for ChangeLogs from these paths. We might find
568 # more than one ChangeLog, in this case the user will be prompted to pick up
570 # Otherwise (no path passed in the command line) the user just wants to
571 # commit the current working directory.
572 # In any case, we schedule "ChangeLog" for commit.
574 # Alright now that we know which ChangeLog to use, we look in the ChangeLog's
575 # directory if there is a ",svn-log" file which would mean that a previous
576 # commit didn't finish successfully. If there is such a file, the user is
577 # prompted to know whether they want to resume that commit or simply start a
579 # When the user wants to resume a commit, the ",svn-log" file is loaded and we
580 # retrieve the value of "$@" that was saved in the file.
581 # Otherwise we build a template ChangeLog entry.
582 # Then we open the template ChangeLog entry with $EDITOR so that the user
584 # Finally, we commit.
585 # Once the commit is sent, we ask the server to know which revision was
586 # commited and we also retrieve the diff. We then send a mail with these.
592 # Check if the user passed some paths to commit explicitly
593 # because in this case we must add the ChangeLog to the commit and search
594 # the ChangeLog from the dirname of that file.
595 i
=0; search_from
=''; add_changelog
=no
; extra_files
=''
596 while [ $i -lt $# ]; do
598 if [ x
"$arg" = x--dry-run
]; then
604 # If the argument is a valid path: add the ChangeLog in the list of
606 if test -e "$arg"; then
608 if test -d "$arg"; then
609 search_from_add
="$arg"
611 search_from_add
=`dirname "$arg"`
613 search_from
="$search_from:$search_from_add"
616 set dummy
"$@" "$arg"
620 if [ $add_changelog = no
]; then
621 # There is no path/file in the command line: the user wants to commit the
622 # current directory. Make it explicit now:
625 search_from
=`echo "$search_from" | sed 's/^://; s/^$/./'`
627 # ----------------- #
628 # Find ChangeLog(s) #
629 # ----------------- #
631 nb_chlogs
=0; change_log_dirs
=''
632 save_IFS
=$IFS; IFS
=':'
633 for dir
in $search_from; do
635 test -z "$dir" && dir
='.'
636 # First: come back to the original place
637 cd "$here" || abort
"Cannot cd to $here"
638 cd "$dir" ||
continue # Then: Enter $dir (which can be a relative path)
640 while [ $found -eq 0 ]; do
641 this_chlog_dir
=`pwd -P`
642 if [ -f .
/ChangeLog
]; then
644 nb_chlogs
=`expr $nb_chlogs + 1`
645 change_log_dirs
="$change_log_dirs:$this_chlog_dir"
649 # Stop searching when in / ... hmz :P
650 test x
"$this_chlog_dir" = x
/ && break
651 done # end while: did we find a ChangeLog
652 done # end for: find ChangeLogs in $search_from
653 if [ $nb_chlogs -gt 0 ]; then
654 change_log_dirs
=`echo "$change_log_dirs" | sed 's/^://' | tr ':' '\n' \
656 nb_chlogs
=`echo "$change_log_dirs" | wc -l`
659 # Did we find a ChangeLog? More than one?
660 if [ $nb_chlogs -eq 0 ]; then
661 if yesno
'svn-wrapper: Error: Cannot find a ChangeLog file!
662 You might want to create an empty one (eg: `touch ChangeLog` where appropriate)
663 Do you want to proceed without using a ChangeLog?'; then
670 elif [ $nb_chlogs -gt 1 ]; then
671 notice
"$nb_chlogs ChangeLogs were found, pick up one:"
674 for a_chlog_dir
in $change_log_dirs; do
676 echo "$i. $a_chlog_dir/ChangeLog"
678 echo -n "Which ChangeLog do you want to use? [1-$i] "
679 read chlog_no || abort
'Cannot read answer on stdin.'
682 *[^
0-9]*) abort
"Invalid ChangeLog number: $chlog_no"
684 test "$chlog_no" -le $i || abort
"Invalid ChangeLog number: $chlog_no
686 test "$chlog_no" -ge 1 || abort
"Invalid ChangeLog number: $chlog_no
688 change_log_dir
=`echo "$change_log_dirs" | tr ':' '\n' | sed "${chlog_no}!d"`
689 else # Only one ChangeLog found
690 change_log_dir
=$change_log_dirs
691 notice
"using $change_log_dir/ChangeLog"
694 test -f "$change_log_dir/ChangeLog" \
695 || abort
"No such file or directory: $change_log_dir/ChangeLog"
697 # Now we can safely schedule the ChangeLog for the commit.
698 extra_files
="$extra_files:$change_log_dir/ChangeLog"
699 if [ -d "$change_log_dir/.git" ]; then
701 repos_url
=`git show | sed '/git-svn-id/{
707 test x
"$repos_url" = x
&& abort
'Could not find git-svn-id in `git show`'
708 repos_root
=$repos_url
710 svn_st_tmp
=`$SVN status "$change_log_dir"`
712 # Warn for files that are not added in the repos.
713 conflicts
=`echo "$svn_st_tmp" | sed '/^ *$/d;
717 if test x
"$conflicts" != x
; then
718 warn
"make sure you don't want to \`svn add'
719 any of the following files before committing:"
720 echo "$conflicts" |
sed "$sed_svn_st_color"
721 echo -n 'Type [ENTER] to continue :)' && read chiche_is_gay
724 # If there are changes in an svn:externals, advise the user to commit that
726 changed_externals
=`echo "$svn_st_tmp" | $AWK \
735 BEGIN { this_ext = ""; ext = 0; ext_modified = 0; }
736 /^Performing status on external/ {
738 sub(/.* at ./, ""); sub(/.$/, ""); this_ext = $0;
741 /^[ADMR]/ { ext_modified = ext; printext(); }
742 /^.[M]/ { ext_modified = ext; printext(); }
743 END { exit ext_modified; }'`
744 if [ $?
-ne 0 ]; then
745 warn
"the following external items have local modifications:
747 yesno
"You are advised to commit them separately first. Continue anyway?" \
751 # Detect unresolved conflicts / missing files.
752 conflicts
=`echo "$svn_st_tmp" | sed '/^[C!]/!d'`
753 test x
"$conflicts" != x
&& abort
"there are unresolved conflicts (\`C')
754 and/or missing files (\`!'):
757 svn_info_tmp
=`$SVN info "$change_log_dir"`
758 test $?
-ne 0 && abort
"Failed to get svn info on $change_log_dir"
759 repos_root
=`echo "$svn_info_tmp" | sed '/^Repository Root: /!d;s///'`
760 repos_url
=`echo "$svn_info_tmp" | sed '/^URL: /!d;s///'`
761 # It looks like svn <1.3 didn't display a "Repository Root" entry.
762 test x
"$repos_root" = x
&& repos_root
=$repos_url
771 # VCS-compat: handle user option 'new_user'
773 grep '^new_user: false' ~
/.vcs
>/dev
/null
2>/dev
/null
&& new_user
='no'
776 tmp_log
="$change_log_dir/,svn-log"
777 if [ -f "$tmp_log" ] && yesnewproceed
"It looks like the last commit did not\
778 terminate successfully.
779 Would you like to resume it or proceed immediately?"; then
780 test x
"$yesnoproceed_res" = xproceed
&& edit_changelog
=no
782 internal_tags
=`sed '/^--- Internal stuff, DO NOT change please ---$/,$!d' \
784 saved_args
=`echo "$internal_tags" | sed '/^args: */!d;s///'`
785 extra_files
=`echo "$internal_tags" | sed '/^extra_files: */!d;s///'`
786 if [ x
"$saved_args" != x
]; then
787 if [ x
"$*" != x
] && [ x
"$saved_args" != x
"$*" ]; then
788 warn
"overriding arguments:
789 you invoked $me with the following arguments: $@
790 they have been replaced by these: $saved_args"
791 set dummy
$saved_args
794 notice
"setting the following arguments: $saved_args"
795 set dummy
$saved_args
798 elif [ x
"$*" != x
]; then
799 warn
"overriding arguments:
800 you invoked $me with the following arguments: $@
801 they have been dropped"
804 get_svn_diff_and_diffstat
"$@"
806 # Update the file with the new diff/diffstat in case it changed.
811 /^--This line, and those below, will be ignored--$/ {
814 /^ Your ChangeLog entry will appear here\.$/ {
815 if (tlatbwbi_seen) ycewah_seen = 1;
818 if (ycewah_seen != 2) print;
819 if (ycewah_seen == 1) ycewah_seen = 2;
820 }' "$tmp_log" >"$tmp_log.tmp"
826 $internal_tags" >>"$tmp_log.tmp"
827 mv -f "$tmp_log.tmp" "$tmp_log"
829 else # Build the template message.
831 # ------------------------------------ #
832 # Gather info for the template message #
833 # ------------------------------------ #
835 if [ x
"$SVN" = xgit
]; then
836 projname
=`grep project "$change_log_dir/.git/svn/git-svn/unhandled.log"`
838 || abort
'Failed to find "project" in git-svn/unhandled.log'
839 sed_tmp
='$!d;s/^.*+dir_prop: . project //'
840 projname
=`echo "$projname" | sed "$sed_tmp"`
842 projname
=`$SVN propget project "$change_log_dir"`
844 # Try to be VCS-compatible and find a project name in a *.rb.
845 if [ x
"$projname" = x
] && [ -d "$change_log_dir/vcs" ]; then
846 projname
=`sed '/common_commit/!d;s/.*"\(.*\)<%= rev.*/\1/' \
847 "$change_log_dir"/vcs/*.rb`
848 test x
"$projname" != x
&& test x
$new_user = xyes \
849 && notice
"VCS-compat: found project name: $projname
850 in " "$change_log_dir"/vcs
/*.rb
852 test x
"$projname" != x
&& projname
=`echo "$projname" | sed '/[^ ]$/s/$/ /'`
854 if [ x
"$SVN" = xgit
]; then
855 mailto
=`grep mailto "$change_log_dir/.git/svn/git-svn/unhandled.log"`
857 || abort
'Failed to find "mailto" in git-svn/unhandled.log'
858 sed_tmp
='$!d;s/^.*+dir_prop: . mailto //;s/%40/@/g;s/%2C/,/g'
859 mailto
=`echo "$mailto" | sed "$sed_tmp"`
861 mailto
=`$SVN propget mailto "$change_log_dir"`
863 if [ x
"$mailto" = x
]; then
864 test x
$new_user = xyes \
865 && warn
"no svn property mailto found in $change_log_dir
866 You might want to set default email adresses using:
867 svn propset mailto 'somebody@mail.com, foobar@example.com'\
869 # Try to be VCS-compatible and find a list of mails in a *.rb.
870 if [ -d "$change_log_dir/vcs" ]; then
871 mailto
=`grep '.@.*\..*' "$change_log_dir"/vcs/*.rb \
873 | sed 's/^.*[["]\([^["]*@[^]"]*\)[]"].*$/\1/' | xargs`
874 test x
"$mailto" != x
&& test x
$new_user = xyes \
875 && notice
"VCS-compat: found mailto: $mailto
876 in " "$change_log_dir"/vcs
/*.rb
878 fi # end guess mailto
880 # Ensure that emails are comma-separated.
881 mailto
=`echo "$mailto" | sed 's/[ ;]/,/g' | tr -s ',' | sed 's/,/, /g'`
882 test x
"$FULLNAME" = x
&& FULLNAME
='Type Your Name Here' \
884 test x
"$EMAIL" = x
&& EMAIL
='your.mail.here@FIXME.com' && warn_env EMAIL
886 if [ x
"$SVN" = xgit
]; then
887 my_svn_st
=`git status`
888 test $?
= 0 || abort
'Nothing to commit (or git status failed)'
889 change_log_files
=`echo "$my_svn_st" | sed '
892 s/^# modified: *\(.*\)$/ * \1: ./; t
893 s/^# new file: *\(.*\)$/ * \1: New./; t
894 s/^# deleted: *\(.*\)$/ * \1: Remove./; t
895 # d < FIXME delete lines once git support works for sur
898 # --ignore-externals appeared after svn 1.1.1
899 my_svn_st
=`$SVN status --ignore-externals "$@" \
900 || $SVN status "$@" | sed '/^Performing status on external/ {
904 # Files to put in the ChangeLog entry.
905 change_log_files
=`echo "$my_svn_st" | sed '
908 s/^M......\(.*\)$/ * \1: ./; t
909 s/^A......\(.*\)$/ * \1: New./; t
910 s/^D......\(.*\)$/ * \1: Remove./; t
913 if [ x
"$change_log_files" = x
]; then
914 yesno
'Nothing to commit, continue anyway?' ||
return 1
918 change_log_files
=`echo "$change_log_files" | sort -u`
920 get_svn_diff_and_diffstat
"$@"
922 # Get any older svn-log out of the way.
923 test -f "$tmp_log" && mv "$tmp_log" `get_unique_file_name "$tmp_log"`
924 # If we can't get an older svn-log out of the way, find a new name...
925 test -f "$tmp_log" && tmp_log
=`get_unique_file_name "$tmp_log"`
926 if [ x
$new_user = no
]; then
927 commit_instructions
='
929 - Fill the ChangeLog entry.
930 - If you feel like, write a comment in the "Comment:" section.
931 This comment will only appear in the email, not in the ChangeLog.
932 By default only the location of the repository is in the comment.
933 - Some tags will be replaced. Tags are of the form: <TAG>. Unknown
934 tags will be left unchanged.
935 - The tag <REV> may only be used in the Subject.
936 - Your ChangeLog entry will be used as commit message for svn.'
938 commit_instructions
=''
941 --You must fill this file correctly to continue-- -*- vcs -*-
943 Subject: ${projname}r<REV>: <TITLE>
944 From: $FULLNAME <$EMAIL>
952 <YYYY>-<MM>-<DD> $FULLNAME <$EMAIL>
957 --This line, and those below, will be ignored--
959 --Preview of the message that will be sent--
962 Your comments (if any) will appear here.
965 $YYYY-$MM-$DD $FULLNAME <$EMAIL>
967 Your ChangeLog entry will appear here.
971 $svn_diff" >"$tmp_log"
974 --- Internal stuff, DO NOT change please ---
975 args: $@" >>"$tmp_log"
976 echo "extra_files: $extra_files
977 vi: ft=diff:noet:" >>"$tmp_log"
979 fi # end: if svn-log; then resume? else create template
980 test x
"$edit_changelog" = xyes
&& $EDITOR "$tmp_log"
982 # ------------------ #
983 # Re-"parse" the log #
984 # ------------------ #
986 # hmz this section is a bit messy...
987 # helper string... !@#$%* escaping \\\\\\...
988 sed_escape
='s/\\/\\\\/g;s/@/\\@/g;s/&/\\\&/g'
989 sed_eval_tags
="s/<MM>/$MM/g; s/<DD>/$DD/g; s/<YYYY>/$YYYY/g"
990 full_log
=`sed '/^--This line, and those below, will be ignored--$/,$d;
991 /^--You must fill this/d' "$tmp_log"`
992 chlog_entry
=`echo "$full_log" | sed '/^ChangeLog:$/,$!d; //d'`
993 ensure_not_empty
'ChangeLog entry' "$chlog_entry"
994 full_log
=`echo "$full_log" | sed '/^ChangeLog:$/,$d'`
995 mail_comment
=`echo "$full_log" | sed '/^Comment:$/,$!d; //d'`
996 full_log
=`echo "$full_log" | sed '/^Comment:$/,$d'`
997 mail_title
=`echo "$full_log" | sed '/^Title: */!d;s///'`
998 ensure_not_empty
'commit title' "$mail_title"
999 mail_title
=`echo "$mail_title" | sed "$sed_eval_tags; $sed_escape"`
1000 sed_eval_tags
="$sed_eval_tags; s@<TITLE>@$mail_title@g"
1001 mail_comment
=`echo "$mail_comment" | sed "$sed_eval_tags"`
1002 chlog_entry
=`echo "$chlog_entry" | sed "$sed_eval_tags; 1{
1005 mail_subject
=`echo "$full_log" | sed '/^Subject: */!d;s///'`
1006 ensure_not_empty
'mail subject' "$mail_subject"
1007 mail_to
=`echo "$full_log" | sed '/^To:/!d'`
1009 if test x
"$mail_to" = x
; then
1012 mail_to
=`echo "$mail_to" | sed 's/^To: *//'`
1013 ensure_not_empty
'"To:" field of the mail' "$mail_to"
1015 mail_from
=`echo "$full_log" | sed '/^From: */!d;s///'`
1016 ensure_not_empty
'"From:" field of the mail' "$mail_from"
1018 if echo "$chlog_entry" |
grep '<REV>' >/dev
/null
; then
1019 warn
'Using the tag <REV> anywhere else than in the Subject is deprecated.'
1020 yesno
'Continue anyway?' ||
return 1
1023 if echo "$chlog_entry" |
grep ': \.$' >/dev
/null
; then
1024 warn
'It looks like you did not fill all entries in the ChangeLog:'
1025 echo "$chlog_entry" |
grep ': \.$'
1026 yesno
'Continue anyway?' ||
return 1
1029 # Check whether the user passed -m | --message
1031 while [ $i -lt $# ]; do
1033 # This is not really a reliable way of knowing whether -m | --message was
1034 # passed but hum... Let's assume it'll do :s
1035 if [ x
"$arg" = 'x-m' ] ||
[ x
"$arg" = 'x--message' ]; then
1039 set dummy
"$@" "$arg"
1043 if [ x
"$my_message" = x
]; then
1044 my_message
=`echo "$chlog_entry" | grep -v "^$YYYY-$MM-$DD" | sed -e '1,2 {
1046 }' -e "$_sed_helper"`
1048 notice
'you are overriding the commit message.'
1051 if [ x
"$dry_run" = xyes
]; then
1052 proposal_file
=',proposal'
1053 test -f "$proposal_file" \
1054 && proposal_file
=`get_unique_file_name "$proposal_file"`
1055 mail_subject
=`echo "$mail_subject" | sed "$sed_eval_tags; s/<REV>/???/g"`
1059 Subject: $mail_subject
1068 $svn_diff" >"$proposal_file"
1069 notice
"A proposal of your commit was left in '$proposal_file'"
1074 yesno
'Are you sure you want to commit?' ||
return 1
1076 # Add the ChangeLog entry
1077 old_chlog
=`get_unique_file_name "$change_log_dir/ChangeLog.old"`
1078 mv "$change_log_dir/ChangeLog" "$old_chlog" || \
1079 abort
'Could not backup ChangeLog'
1080 trap "echo SIGINT; mv \"$old_chlog\" \"$change_log_dir/ChangeLog\";
1082 echo "$chlog_entry" >"$change_log_dir/ChangeLog"
1083 echo >>"$change_log_dir/ChangeLog"
1084 cat "$old_chlog" >>"$change_log_dir/ChangeLog"
1086 # Add extra files such as cwd or ChangeLog to the commit.
1087 tmp_sed
='s/ /\\ /g' # Escape spaces for the shell.
1088 if [ x
"$SVN" = xgit
]; then
1089 # Schedule the ChangeLog for the next commit
1090 git add
"$change_log_dir/ChangeLog" \
1091 || abort
'failed to git add the ChangeLog'
1094 extra_files
=`echo "$extra_files" | sed "$tmp_sed" | tr ':' '\n'`
1097 # --Commit-- finally! :D
1098 $SVN commit
-m "$my_message" "$@" $extra_files ||
{
1100 mv "$old_chlog" "$change_log_dir/ChangeLog"
1101 abort
"Commit failed, $SVN returned $svn_commit_rv"
1104 echo -n 'Getting the revision number... '
1105 if [ x
"$SVN" = xgit
]; then
1106 REV
=`git-show --pretty=format:%h | sed q`
1108 svn_info_tmp
=`$SVN info "$change_log_dir/ChangeLog"`
1109 REV
=`echo "$svn_info_tmp" | sed '/^Revision: /!d;s///'`
1110 test x
"$REV" = x
&& REV
=`echo "$svn_info_tmp" \
1111 | sed '/^Last Changed Rev: /!d;s///'`
1113 test x
"$REV" = x
&& abort
'Cannot detect the current revision.'
1116 # Let's make sure we have the real diff by asking the ChangeSet we've just
1117 # committed to the server.
1119 # Backup the old stuff in case we fail to get the real diff from the server
1120 # for some reason...
1121 save_svn_diff
=$svn_diff
1122 save_svn_diff_stat
=$svn_diff_stat
1124 if [ x
"$SVN" = xgit
]; then
1125 svn_diff
=`git diff --ignore-space-change --no-color -C 'HEAD^' HEAD`
1126 svn_diff_stat
=`git diff --stat --ignore-space-change --no-color -C 'HEAD^' HEAD`
1127 notice
'Do not forget to use: git-svn dcommit to push your commits in SVN'
1129 # Fetch the ChangeSet and filter out the ChangeLog entry. We don't use
1130 # svn diff -c because this option is not portable to older svn versions.
1131 REV_MINUS_ONE
=`expr "$REV" - 1`
1132 svn_diff
=`svn_diffw -r"$REV_MINUS_ONE:$REV" "$repos_root" \
1133 | $AWK '/^Index: / { if (in_chlog) in_chlog = 0; }
1134 /^Index: .*ChangeLog$/ { in_chlog = 1 }
1135 { if (!in_chlog) print }'`
1136 if [ x
"$svn_diff" = x
]; then
1137 svn_diff
=$save_svn_diff
1138 svn_diff_stat
=$save_svn_diff_stat
1140 if require_diffstat
; then
1141 svn_diff_stat
=`echo "$svn_diff" | diffstat`
1143 svn_diff_stat
='diffstat not available'
1148 mail_subject
=`echo "$mail_subject" | sed "$sed_eval_tags; s/<REV>/$REV/g"`
1150 mail_file
=`get_unique_file_name "$change_log_dir/+mail"`
1154 Subject: $mail_subject
1163 $svn_diff" |
sed 's/^\.$/ ./' >"$mail_file"
1164 # We change lines with only a `.' because they could mean "end-of-mail"
1167 if test x
$send_a_mail = xyes
; then
1168 trap 'echo SIGINT; exec < /dev/null' $SIGINT
1169 # FIXME: Move the mail to the +committed right now, in case the user
1170 # CTLR+C the mail-sending-thing, so that the mail will be properly saved
1172 my_sendmail
"$mail_file" "$mail_subject" "$mail_to" \
1173 "X-svn-url: $repos_root
1174 X-svn-revision: $REV"
1175 fi # end do we have to send a mail?
1178 save_mail_file
=`echo "$mail_file" | sed 's/+//'`
1179 mkdir
-p "$change_log_dir/+committed" \
1180 || warn
"Couldn't mkdir -p $change_log_dir/+committed"
1181 if [ -d "$change_log_dir/vcs" ] \
1182 ||
[ -d "$change_log_dir/+committed" ]
1184 mkdir
-p "$change_log_dir/+committed/$REV" \
1185 && mv "$mail_file" "$change_log_dir/+committed/$REV/mail"
1187 return $svn_commit_rv
1193 i
=0; src
=''; dst
=''; rev1
=''; rev2
=''; r_seen
=0
1194 while [ $i -lt $# ]; do
1196 if test -d "$arg"; then
1197 if [ x
"$src" = x
]; then
1199 elif [ x
"$dst" = x
]; then
1204 -r*:*) rev1
=`echo "$arg" | sed 's/^[^PREVHEAD0-9]*//; s/:.*//'`
1205 rev2
=`echo "$arg" | sed 's/^.*://; s/[^PREVHEAD0-9]*//'`
1211 set dummy
"$@" "$arg"
1215 if [ x
"$src" = x
]; then
1216 exec $SVN merge
"$@"
1218 test x
"$dst" = x
&& dst
='.'
1220 if yesno
"Do you want to use the automerge feature for $src ?";
1222 exec $SVN merge
"$@"
1224 # FIXME: Incomplete.
1227 # svn_automerge src-path dst-path
1230 test -f ChangeLog || abort
'You must use automerge in the folder where the
1232 amerge
=`$SVN propget automerge`
1233 if [ x
"$amerge" = x
]; then
1234 # FIXME: Use svn log --stop-on-copy to detect the original branching.
1238 svn_info_tmp
=`$SVN info`
1239 REV
=`echo "$svn_info_tmp" | sed '/^Revision: /!d;s///'`
1240 test x
"$REV" = x
&& REV
=`echo "$svn_info_tmp" \
1241 | sed '/^Last Changed Rev: /!d;s///'`
1242 test x
"$REV" = x
&& abort
'Cannot detect the current revision.'
1244 # FIXME: Incomplete.
1245 if yesno
"Are you sure you want to run:
1246 $SVN merge -r$amerge:$REV $1 $2 ?"; then
1247 $SVN merge
"-r$amerge:$REV" "$1" "$2"
1251 # svn_diffw [args...]
1254 # Ignore white spaces. Can't svn diff -x -w: svn 1.4 only.
1255 if [ x
"$SVN" = xgit
]; then
1256 git
diff --ignore-space-change --no-color -C HEAD
1258 $SVN diff --no-diff-deleted --diff-cmd diff -x -uw "$@"
1262 # svn_mail REV [mails...]
1265 test $# -lt 1 && abort
"Not enough arguments provided;
1266 Try 'svn help mail' for more info."
1269 REV
=`svn_revision || abort 'Cannot get current revision number'`
1270 test x
"$REV" = x
&& abort
'Cannot get current revision number'
1271 if [ "$REV" -lt 1 ]; then
1272 abort
'No previous revision.'
1274 REV
=`expr "$REV" - 1`
1277 REV
=`svn_revision || abort 'Cannot get current revision number'`
1278 test x
"$REV" = x
&& abort
'Cannot get current revision number'
1280 *[^
0-9]*) abort
"Syntax error in revision argument '$1'";;
1285 found_committed
=0; found
=0
1286 while [ $found -eq 0 ]; do
1287 this_chlog_dir
=`pwd -P`
1288 if [ -d .
/+committed
]; then
1290 if [ -d .
/+committed
/$REV ]; then
1298 # Stop searching when in / ... hmz :P
1299 test x
`pwd` = x
/ && break
1301 if [ $found -eq 0 ]; then
1302 if [ $found_committed -eq 0 ]; then
1303 abort
'Could not find the +committed directory.'
1305 abort
"Could not find the revision $REV in +committed."
1307 abort
'Internal error (should never be here).'
1310 mail_file
=''; subject
=''; to
=''
1311 if [ -f .
/+committed
/$REV/mail ]; then
1312 # svn-wrapper generated file
1313 mail_file
="./+committed/$REV/mail"
1314 subject
=`sed '/^Subject: /!d;s///' $mail_file | sed '1q'`
1315 to
=`sed '/^To: /!d;s///' $mail_file | sed '1q'`
1316 elif [ -f .
/+committed
/$REV/,iform
] && [ -f .
/+committed
/$REV/,message
]
1318 # VCS-generated file
1319 subject
=`sed '/^Subject: /!d;s///;s/^"//;s/"$//' ./+committed/$REV/,iform \
1320 | sed "s/<%= *rev *%>/$REV/g"`
1321 to
=`sed '/^To:/,/^[^-]/!d' ./+committed/$REV/,iform | sed '1d;s/^- //;$d' \
1322 | xargs | sed 's/ */, /g'`
1323 mail_file
=`get_unique_file_name "$TMPDIR/mail.r$REV"`
1324 echo "From: $FULLNAME <$EMAIL>
1327 " >"$mail_file" || abort
"Cannot create $mail_file"
1328 cat .
/+committed
/$REV/,message
>>"$mail_file" \
1329 || abort
"Cannot copy ./+committed/$REV/,message in $mail_file"
1331 abort
"Couldn't find the mail to re-send in `pwd`/+committed/$REV"
1333 if [ $# -gt 0 ]; then
1334 to
=`echo "$*" | sed 's/ */, /g'`
1337 test x
"$to" = x
&& abort
'Cannot find the list of recipients.
1338 Please report this bug.'
1339 test x
"$subject" = x
&& abort
'Cannot find the subject of the mail.
1340 Please report this bug.'
1342 if yesno
"Re-sending the mail of r$REV
1345 Are you sure?"; then :; else
1349 svn_info_tmp
=`$SVN info`
1350 test $?
-ne 0 && abort
"Failed to get svn info on `pwd`"
1351 repos_root
=`echo "$svn_info_tmp" | sed '/^Repository Root: /!d;s///'`
1352 repos_url
=`echo "$svn_info_tmp" | sed '/^URL: /!d;s///'`
1353 # It looks like svn <1.3 didn't display a "Repository Root" entry.
1354 test x
"$repos_root" = x
&& repos_root
=$repos_url
1356 my_sendmail
"$mail_file" "$subject" "$to" \
1357 "X-svn-url: $repos_url
1358 X-svn-revision: $REV"
1364 echo "Using svn-wrapper v$version (C) SIGOURE Benoit [GPL]"
1365 sed '/^# $Id[:].*$/!d;s/.*$Id[:] *//;s/ *$ *//;s/ \([0-9][0-9]*\)/ (r\1)/' "$me"
1368 # has_prop prop-name [path]
1369 # return value: 0 -> path has the property prop-name set.
1370 # 1 -> path has no property prop-name.
1374 hp_plist
=`$SVN proplist "$2"`
1375 test $?
-ne 0 && return 2
1376 hp_res
=`echo "$hp_plist" | sed "/^ *$1\$/!d"`
1377 test x
"$hp_res" = x
&& return 1
1381 # svn_propadd prop-name prop-val [path]
1385 && abort
'Not enough arguments provided;
1386 try `svn help propadd` for more info'
1388 && abort
'Too many arguments provided;
1389 try `svn help propadd` for more info'
1392 test x
"$path" = x
&& path
='.' && set dummy
"$@" '.' && shift
1393 has_prop
"$1" "$3" ||
{
1394 test $?
-eq 2 && return 1 # svn error
1395 # no property found:
1396 yesno
"'$path' has no property named '$1', do you want to add it?" \
1397 && $SVN propset
"$@"
1401 current_prop_val
=`$SVN propget "$1" "$3"`
1402 test $?
-ne 0 && abort
"Failed to get the current value of property '$1'."
1404 $SVN propset
"$1" "$current_prop_val
1405 $2" "$3" >/dev
/null || abort
"Failed to add '$3' in the property '$1'."
1407 current_prop_val
=`$SVN propget "$1" "$3" || echo "$current_prop_val
1409 echo "property '$1' updated on '$path', new value:
1413 # svn_propsed prop-name sed-script [path]
1417 && abort
'Not enough arguments provided;
1418 try `svn help propsed` for more info'
1420 && abort
'Too many arguments provided;
1421 try `svn help propsed` for more info'
1424 test x
"$path" = x
&& path
='.'
1425 has_prop
"$1" "$3" ||
{
1426 test $?
-eq 2 && return 1 # svn error
1427 # no property found:
1428 abort
"'$path' has no property named '$1'."
1431 prop_val
=`$SVN propget "$1" "$3"`
1432 test $?
-ne 0 && abort
"Failed to get the current value of property '$1'."
1434 prop_val
=`echo "$prop_val" | sed "$2"`
1435 test $?
-ne 0 && abort
"Failed to run the sed script '$2'."
1437 $SVN propset
"$1" "$prop_val" "$3" >/dev
/null \
1438 || abort
"Failed to update the property '$1' with value '$prop_val'."
1440 new_prop_val
=`$SVN propget "$1" "$3" || echo "$prop_val"`
1441 echo "property '$1' updated on '$path', new value:
1445 # svn_revision [args...]
1448 svn_revision_info_out
=`$SVN info "$@"`
1450 echo "$svn_revision_info_out" |
sed '/^Revision: /!d;s///'
1451 return $svn_revision_rv
1454 # svn_ignore [paths]
1457 if [ $# -eq 0 ]; then # Simply display ignore-list.
1458 $SVN propget
'svn:ignore'
1459 elif [ $# -eq 1 ]; then
1460 svn_propadd
'svn:ignore' `basename "$1"` `dirname "$1"`
1461 else # Add arguments in svn:ignore.
1462 # This part is a bit tricky:
1463 # For each argument, we find all the other arguments with the same dirname
1464 # $dname and we svn:ignore them all in $dname.
1465 while [ $# -ne 0 ]; do
1467 dname
=`dirname "$1"`
1468 files
=`basename "$1"`
1471 while [ $j -lt $argc ] && [ $# -ne 0 ]; do
1474 this_dname
=`dirname "$this_arg"`
1475 this_file
=`basename "$this_arg"`
1476 if [ x
"$dname" = x
"$this_dname" ]; then
1480 set dummy
"$@" "$this_arg"
1485 svn_propadd
'svn:ignore' "$files" "$dname"
1493 if [ $# -eq 0 ]; then
1498 Additionnal commands provided by svn-wrapper:
1499 automerge (amerge, am)
1514 automerge | auto-merge | amerge | am
)
1515 echo 'automerge (amerge, am): FIXME
1516 usage: automerge FIXME
1521 $SVN help commit |
sed '/^Valid options:/a\
1522 \ --dry-run : do not commit, simply generate a patch with what\
1523 \ would have been comitted (svn-wrapper extension).
1528 echo 'diffstat (ds): Display the histogram from svn diff-output.'
1529 $SVN help diff |
sed '1d;
1530 s/differences*/histogram/;
1531 2,35 s/diff/diffstat/g'
1534 echo "diffw (dw): Display the differences without taking whitespaces\
1536 $SVN help diff |
sed '1d;
1537 2,35 s/diff\([^a-z]\)/diffw\1/g;
1538 /--diff-cmd/,/--no-diff-deleted/d'
1541 echo 'ignore: Add some files in the svn:ignore property.
1542 usage: 1. ignore [PATH]
1543 2. ignore FILE [FILES...] [PATH]
1545 1. Display the value of svn:ignore property on [PATH].
1546 2. Add some files in the svn:ignore property of [PATH].
1548 If you want to add directories in the ignore-list, be careful:
1549 svn ignore foo/ bar/
1550 will add "foo/" in the property svn:ignore within the directory bar!
1552 svn ignore foo/ bar/ .
1553 (It'\''s somewhat like with mv)
1559 echo 'mail: Resend the mail of a given commit.
1560 usage: mail REV [emails]
1562 REV must have an email file associated in +committed/REV.
1563 REV can also be PREV or HEAD.
1565 By default the mail is sent to same email addresses as during the original
1566 commit unless more arguments are given.'
1568 propadd | padd | pa
)
1569 echo 'propadd (padd, pa): Add something in the value of a property.
1570 usage: propadd PROPNAME PROPVAL PATH
1572 PROPVAL will be appended at the end of the property PROPNAME.
1578 echo 'proposal: Alias for: commit --dry-run.
1579 See: svn help commit.'
1582 echo 'propsed (psed): Edit a property with sed.
1583 usage: propsed PROPNAME SED-ARGS PATH
1585 eg: svn propsed svn:externals "s/http/https/" .
1591 echo 'revision (rev): Display the revision number of a local or remote item.'
1592 $SVN help info |
sed '1d;
1593 s/information/revision/g;
1594 s/revision about/the revision of/g;
1595 2,35 s/info/revision/g;
1599 echo 'touch: Touch a file and svn add it.
1600 usage: touch FILE [FILES]...
1605 selfupdate | selfup | self-update | self-up
)
1606 echo 'selfupdate (selfup): Attempt to update svn-wrapper.sh
1613 echo 'version: Display the version info of svn and svn-wrapper.
1624 # svn_status [args...]
1627 svn_status_out
=`$SVN status "$@"`
1629 test x
"$svn_status_out" = x
&& return $svn_status_rv
1630 echo "$svn_status_out" |
sed "$sed_svn_st_color"
1631 return $svn_status_rv
1634 # svn_update [args...]
1637 svn_update_out
=`$SVN update "$@"`
1639 echo "$svn_update_out" |
sed "$sed_svn_up_colors"
1640 return $svn_update_rv
1643 # ------------------- #
1644 # `main' starts here. #
1645 # ------------------- #
1647 # Define colors if stdout is a tty.
1650 else # stdout isn't a tty => don't print colors.
1654 # Consider this as a sed function :P.
1658 s@^?\\(......\\)+@+\\1+@
1659 s@^?\\(......\\)\\(.*/\\)+@+\\1\\2+@
1660 s@^?\\(......\\),@,\\1,@
1661 s@^?\\(......\\)\\(.*/\\),@,\\1\\2,@
1662 s/^\\(.\\)C/\\1${lred}C${std}/
1665 s/^?/${lred}?${std}/; t
1666 s/^M/${lgreen}M${std}/; t
1667 s/^A/${lgreen}A${std}/; t
1668 s/^X/${lblue}X${std}/; t
1669 s/^+/${lyellow}+${std}/; t
1670 s/^D/${lyellow}D${std}/; t
1671 s/^,/${lred},${std}/; t
1672 s/^C/${lred}C${std}/; t
1673 s/^I/${purple}I${std}/; t
1674 s/^R/${lblue}R${std}/; t
1675 s/^!/${lred}!${std}/; t
1676 s/^~/${lwhite}~${std}/; t"
1685 s/^\\(.\\)C/\\1${lred}C${std}/
1686 s/^\\(.\\)U/\\1${lgreen}U${std}/
1687 s/^\\(.\\)D/\\1${lred}D${std}/
1690 s/^A/${lgreen}A${std}/; t
1691 s/^U/${lgreen}U${std}/; t
1692 s/^D/${lyellow}D${std}/; t
1693 s/^G/${purple}G${std}/; t
1694 s/^C/${lred}C${std}/; t"
1697 test "x$1" = x--debug
&& shift && set -x
1700 # ------------------------------- #
1701 # Hooks for standard SVN commands #
1702 # ------------------------------- #
1724 # -------------------- #
1725 # Custom SVN commands #
1726 # -------------------- #
1727 automerge | auto-merge | amerge | am
)
1729 if [ $# -ne 2 ]; then
1730 abort
"automerge: not enough arguments provided;
1731 try 'svn help automerge' for more info"
1737 if [ -d .git
]; then
1738 git
diff --stat --no-color -C HEAD
1740 require_diffstat
&& $SVN diff --no-diff-deleted "$@" | diffstat
1755 propadd | padd | pa
)
1761 svn_commit
--dry-run "$@"
1773 touch "$@" && $SVN add
"$@"
1775 selfupdate | selfup | self-update | self-up
)
1779 version |
-version |
--version)
1781 set dummy
'--version' "$@"