TMPDIR is /tmp by default.
[svn-wrapper.git] / svn-wrapper.sh
blobd687b1b29e237052ccc9859d9f19a21702560c55
1 #! /bin/sh
2 # Simple wrapper around svn featuring auto-ChangeLog entries and emailing.
3 # $Id$
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,
19 # USA.
21 # Quick install: alias svn=path/to/svn-wrapper.sh -- that's all.
23 # ------ #
24 # README #
25 # ------ #
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
37 # your problem.
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 :)
42 # ------------- #
43 # DOCUMENTATION #
44 # ------------- #
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
52 # you're looking for.
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>.
59 # ---- #
60 # TODO #
61 # ---- #
63 # * Customizable behavior/colors via some ~/.<config>rc file (?)
64 # * Improve Auto-Emailing (if possible in sh :|)
68 # Default values (the user can export them to override them).
69 : ${SVN=svn}
70 : ${EDITOR=vi}
71 export EDITOR
72 : ${GPG=gpg}
73 : ${TMPDIR=/tmp}
74 export TMPDIR
75 : ${PAGER=more}
76 export PAGER
78 # No args, invoke svn...
79 test $# -lt 1 && exec $SVN
81 version='0.2'
83 # The `main' really starts after the functions definitions.
85 # ---------------- #
86 # Helper functions #
87 # ---------------- #
89 set_colors()
91 red='\e[0;31m'; lred='\e[1;31m'
92 green='\e[0;32m'; lgreen='\e[1;32m'
93 yellow='\e[0;33m'; lyellow='\e[1;33m'
94 blue='\e[0;34m'; lblue='\e[1;34m'
95 purple='\e[0;35m'; lpurple='\e[1;35m'
96 cyan='\e[0;36m'; lcyan='\e[1;36m'
97 grey='\e[0;37m'; lgrey='\e[1;37m'
98 white='\e[0;38m'; lwhite='\e[1;38m'
99 std='\e[m'
102 set_nocolors()
104 red=''; lred=''
105 green=''; lgreen=''
106 yellow=''; lyellow=''
107 blue=''; lblue=''
108 purple=''; lpurple=''
109 cyan=''; lcyan=''
110 grey=''; lgrey=''
111 white=''; lwhite=''
112 std=''
115 # abort err-msg
116 abort()
118 echo "svn-wrapper: abort: $@" | sed '1!s/^/ /' >&2
119 exit 1
122 # warn msg
123 warn()
125 echo "svn-wrapper: warning: $@" | sed '1!s/^/ /' >&2
128 # notice msg
129 notice()
131 echo "svn-wrapper: notice: $@" | sed '1!s/^/ /' >&2
134 # yesno question
135 yesno()
137 echo -n "$@ [y/N] "
138 read answer || return 1
139 case "$answer" in
140 y* | Y*) return 0;;
141 *) return 1;;
142 esac
143 return 42 # should never happen...
146 # warn_env env-var
147 warn_env()
149 echo "svn-wrapper: warning: cannot find the environment variable $1
150 You might consider using \`export $1 proper-value\`" >&2
153 # get_unique_file_name file-name
154 get_unique_file_name()
156 test -f "$1" || {
157 echo "$1" && return 0
159 gufn="$1"; i=1
160 while test -f "$gufn.$i"; do
161 i=`expr $i + 1`
162 done
163 echo "$gufn.$i"
166 # ensure_not_empty description value
167 ensure_not_empty()
169 ene_val=`echo "$2" | tr -d ' \t\n'`
170 test x"$ene_val" = x && abort "$1: empty value"
173 # selfupdate
174 selfupdate()
176 my_url='http://www.lrde.epita.fr/~sigoure/svn-wrapper/'
177 # You can use https if you feel paranoiac.
179 echo ">>> Fetching svn-wrapper.sh from $my_url/svn-wrapper.sh"
180 tmp_me=`get_unique_file_name "$TMPDIR/svn-wrapper.sh"`
181 if wget --help >/dev/null 2>/dev/null; then
182 wget --no-check-certificate "$my_url/svn-wrapper.sh" -O "$tmp_me"
183 my_wget='wget'
184 else
185 curl --help >/dev/null 2>/dev/null
186 my_wget='curl'
187 if [ $? -gt 42 ]; then
188 abort 'Cannot find wget or curl.
189 How can I download any update without them?'
191 curl --insecure "$my_url/svn-wrapper.sh" >"$tmp_me"
193 test -r $tmp_me \
194 || abort "Can't find the copy of myself I downloaded in $tmp_me"
196 tmp_ver=`sed '/^# $Id$/!d;
197 s/.*$Id$ *//;
198 s/ \([0-9][0-9]*\)/\1/' "$tmp_me"`
199 my_ver=`sed '/^# $Id$/!d;
200 s/.*$Id$ *//;
201 s/ \([0-9][0-9]*\)/\1/' "$0"`
202 if [ $my_ver -lt $tmp_ver ]; then
203 yesno "An update is available, r$tmp_ver (your version is r$my_ver)
204 Do you want to install it?" || return 1
205 if yesno "Do you want to see the ChangeLog between r$my_ver and r$tmp_ver?"
206 then
207 my_chlog=`get_unique_file_name "$TMPDIR/ChangeLog"`
208 case $my_wget in
209 wget) wget --no-check-certificate "$my_url/ChangeLog" -o "$my_chlog"
211 curl) curl --insecure "$my_url/ChangeLog" >"$my_chlog"
213 *) abort 'Should never be here.'
215 esac
216 sed "/^r$my_ver/q" "$my_chlog" | $PAGER
218 if yesno "Do you want to see the diff between r$my_ver and r$tmp_ver?"
219 then
220 (diff -u "$0" "$tmp_me" | diffstat;
221 echo
222 diff -u "$0" "$tmp_me") | $PAGER
224 if yesno "Overwrite $0 (r$my_ver) with $tmp_me (r$tmp_ver)?"; then
225 mv "$tmp_me" "$0" && exit 0
227 rm -f "$tmp_me"
228 return 1
229 elif [ $my_ver -gt $tmp_ver ]; then
230 echo "Wow, you're more up to date than the master copy :)"
231 echo "Your version is r$my_ver and the master copy is r$tmp_ver."
232 else
233 echo "You're already up to date :)"
235 rm -f "$tmp_me"
238 # ------------------------------- #
239 # Hooks for standard SVN commands #
240 # ------------------------------- #
242 # svn_commit [args...]
243 svn_commit()
245 # -------------- #
246 # Find ChangeLog #
247 # -------------- #
249 here=`pwd`; found=0; change_log_files=''
250 while [ $found -eq 0 ]; do
251 if [ -f ./ChangeLog ]; then
252 found=1
253 else
254 cd ..
256 change_log_dir=`pwd -P`
257 # Stop searching when in / ... hmz :P
258 test x"$change_log_dir" = x/ && {
259 if yesno 'svn-wrapper: Error: Cannot find a ChangeLog file!
260 You might want to create an empty one (eg: `touch ChangeLog` where appropriate)
261 Do you want to proceed without using a ChangeLog?'; then
262 cd "$here"
263 $SVN commit "$@" && $SVN update
264 return $?
265 else
266 return 1
269 done
270 echo "svn-wrapper: using $change_log_dir/ChangeLog"
272 $SVN update || abort 'svn update failed.'
274 # Warn for files that are not added in the repos.
275 conflicts=`$SVN status | sed '/^\?/!d'`
276 test x"$conflicts" != x && warn "make sure you don't want to \`svn add'
277 any of the following files before committing:" \
278 && echo "$conflicts" | sed "$sed_svn_st_color"
280 # Detect unresolved conflicts / missing files.
281 conflicts=`$SVN status | sed '/^[C!]/!d'`
282 test x"$conflicts" != x && abort "there are unresolved conflicts (\`C')
283 and/or missing files (\`!'):
284 $conflicts"
286 YYYY=`date '+%Y'`
287 MM=`date '+%m'`
288 DD=`date '+%d'`
289 REV=`$SVN info | sed '/^Revision: /!d;s///'`
290 test x"$REV" = x && REV=`$SVN info | sed '/^Last Changed Rev: /!d;s///'`
291 test x"$REV" = x && warn 'Cannot detect the current revision.'
292 REV=`expr $REV + 1`
294 tmp_log="$change_log_dir/svn-log"
295 if [ -f "$tmp_log" ] && yesno "It looks like the last commit did not\
296 terminate successfully.
297 Would you like to resume it?"; then
298 echo 'Resuming ...'
299 internal_tags=`sed '/^--- Internal stuff, DO NOT change please ---$/,$!d' \
300 "$tmp_log"`
301 saved_args=`echo "$internal_tags" | sed '/^args: */!d;s///'`
302 if [ x"$saved_args" != x ]; then
303 if [ x"$@" != x ] && [ x"$saved_args" != x"$@" ]; then
304 warn "overriding arguments:
305 you invoked $0 with the following arguments: $@
306 they have been replaced by these: $saved_args"
307 set dummy "$saved_args"
308 shift
309 else
310 notice "setting the following arguments: $saved_args"
311 set dummy "$saved_args"
312 shift
315 svn_diff=`$SVN diff "$@"`
316 svn_diff_stat=`echo "$svn_diff" | diffstat`
318 else # Build the template message.
320 # ------------------------------------ #
321 # Gather info for the template message #
322 # ------------------------------------ #
324 repos_root=`$SVN info | sed '/^Repository Root/!d;s/^Repository Root: //'`
325 # It looks like svn <1.3 didn't display a "Repository Root" entry.
326 test x"$repos_root" = x && \
327 repos_root=`$SVN info | sed '/^URL/!d;s/^URL: //'`
328 cd "$here"
330 projname=`$SVN propget project "$change_log_dir"`
331 # Try to be VCS-compatible and find a project name in a *.rb.
332 if [ x"$projname" = x ] && [ -d "$change_log_dir/vcs" ]; then
333 projname=`sed '/common_commit/!d;s/.*"\(.*\)<%= rev.*/\1/' \
334 "$change_log_dir"/vcs/*.rb`
335 test x"$projname" != x \
336 && notice "VCS-compat: found project name: $projname
337 in " "$change_log_dir"/vcs/*.rb
339 test x"$projname" != x && projname=`echo "$projname" | sed '/[^ ]$/s/$/ /'`
341 mailto=`$SVN propget mailto "$change_log_dir"`
342 if [ x"$mailto" = x ]; then
343 warn "no svn property mailto found in $change_log_dir
344 You might want to set default email adresses using:
345 svn propset mailto 'somebody@mail.com, foobar@example.com'\
346 $change_log_dir" >&2
347 # Try to be VCS-compatible and find a list of mails in a *.rb.
348 if [ -d "$change_log_dir/vcs" ]; then
349 mailto=`grep '.@.*\..*' "$change_log_dir"/vcs/*.rb \
350 | tr '\n' ' ' \
351 | sed 's/^.*[["]\([^["]*@[^]"]*\)[]"].*$/\1/' | xargs`
352 test x"$mailto" != x && notice "VCS-compat: found mailto: $mailto
353 in " "$change_log_dir"/vcs/*.rb
354 fi # end VCS compat
355 fi # end guess mailto
357 # Ensure that emails are comma-separated.
358 mailto=`echo "$mailto" | sed 's/[ ;]/,/g' | tr -s ',' | sed 's/,/, /g'`
359 test x"$FULLNAME" = x && FULLNAME='Type Your Name Here' \
360 && warn_env FULLNAME
361 test x"$EMAIL" = x && EMAIL='your.mail.here@FIXME.com' && warn_env EMAIL
363 # --ignore-externals appeared after svn 1.1.1
364 my_svn_st=`$SVN status --ignore-externals "$@" \
365 || $SVN status "$@" | sed '/^Performing status on external/ {
370 # Files to put in the ChangeLog entry.
371 change_log_files=`echo "$my_svn_st" | sed '
372 s/^M......\(.*\)$/ * \1: ./; t
373 s/^A......\(.*\)$/ * \1: New./; t
374 s/^D......\(.*\)$/ * \1: Remove./; t
377 if [ x"$change_log_files" = x ]; then
378 yesno 'Nothing to commit, continue anyway?' || return 1
381 svn_diff=`$SVN diff "$@"`
382 svn_diff_stat=`echo "$svn_diff" | diffstat`
384 # Get any older svn-log out of the way.
385 test -f "$tmp_log" && mv "$tmp_log" `get_unique_file_name "$tmp_log"`
386 # If we can't get an older svn-log out of the way, find a new name...
387 test -f "$tmp_log" && tmp_log=`get_unique_file_name "$tmp_log"`
388 echo "\
389 --You must fill this file correctly to continue-- -*- vcs -*-
390 Title:
391 Subject: ${projname}r<REV>: <TITLE>
392 From: $FULLNAME <$EMAIL>
393 To: $mailto
395 Comment:
396 Repository: $repos_root
398 ChangeLog:
400 <YYYY>-<MM>-<DD> $FULLNAME <$EMAIL>
402 r<REV>: <TITLE>
404 $change_log_files
406 --This line, and those below, will be ignored--
408 Instructions:
409 - Fill the ChangeLog entry.
410 - If you feel like, write a comment in the 'Comment:' section.
411 This comment will only appear in the email, not in the ChangeLog.
412 By default only the location of the repository is in the comment.
413 - Some tags will be replaced. Tags are of the form: <TAG>. Unknown
414 tags will be left unchanged.
415 - Your ChangeLog entry will be used as commit message for svn.
417 --Preview of the message that will be sent--
419 Repository: $repos_root
420 Your comments (if any) will appear here.
422 ChangeLog:
423 $YYYY-$MM-$DD $FULLNAME <$EMAIL>
425 Your ChangeLog entry will appear here.
427 $svn_diff_stat
429 $svn_diff" >"$tmp_log"
431 echo "
432 --- Internal stuff, DO NOT change please ---
433 args: $@" >>"$tmp_log"
435 fi # end: if svn-log; then resume? else create template
436 $EDITOR "$tmp_log"
438 # ------------------ #
439 # Re-"parse" the log #
440 # ------------------ #
442 # hmz this section is a bit messy...
443 sed_escape='s/@/\\@/' # helper string... !@#$%* escaping \\\\\\...
444 sed_eval_tags="s/<MM>/$MM/g; s/<DD>/$DD/g; s/<YYYY>/$YYYY/g; s/<REV>/$REV/g"
445 full_log=`sed '/^--This line, and those below, will be ignored--$/,$d;
446 /^--You must fill this/d' "$tmp_log"`
447 chlog_entry=`echo "$full_log" | sed '/^ChangeLog:$/,$!d; /^ChangeLog:$/d'`
448 ensure_not_empty 'ChangeLog entry' "$chlog_entry"
449 full_log=`echo "$full_log" | sed '/^ChangeLog:$/,$d'`
450 mail_comment=`echo "$full_log" | sed '/^Comment:$/,$!d; /^Comment:$/d'`
451 full_log=`echo "$full_log" | sed '/^Comment:$/,$d'`
452 mail_title=`echo "$full_log" | sed '/^Title:/!d;s/^Title: *//'`
453 ensure_not_empty 'commit title' "$mail_title"
454 mail_title=`echo "$mail_title" | sed "$sed_eval_tags; $sed_escape"`
455 sed_eval_tags="$sed_eval_tags; s@<TITLE>@$mail_title@g"
456 mail_comment=`echo "$mail_comment" | sed "$sed_eval_tags"`
457 chlog_entry=`echo "$chlog_entry" | sed "$sed_eval_tags; 1{
458 /^ *$/d
460 mail_subject=`echo "$full_log" | sed '/^Subject:/!d;s/^Subject: *//'`
461 ensure_not_empty 'mail subject' "$mail_subject"
462 mail_subject=`echo "$mail_subject" | sed "$sed_eval_tags"`
463 mail_to=`echo "$full_log" | sed '/^To:/!d;s/^To: *//'`
464 ensure_not_empty '"To:" field of the mail' "$mail_to"
465 mail_from=`echo "$full_log" | sed '/^From:/!d;s/^From: *//'`
466 ensure_not_empty '"From:" field of the mail' "$mail_from"
468 # Check whether the user passed -m | --message
469 i=0; has_message=0
470 while [ $i -lt $# ]; do
471 arg="$1"
472 # This is not really a reliable way of knowing whether -m | --message was
473 # passed but hum... Let's assume it'll do :s
474 test x"$arg" = 'x-m' && has_message=1
475 test x"$arg" = 'x--message' && has_message=1
476 shift
477 set dummy "$@" "$arg"
478 shift
479 i=`expr $i + 1`
480 done
481 if [ $has_message -eq 0 ]; then
482 my_message=`echo "$chlog_entry" | grep -v "^$YYYY-$MM-$DD" | sed '1,2 {
483 /^ *$/d
485 set dummy --message "$my_message" "$@"
486 shift
487 else
488 notice 'you are overriding the commit message.'
491 # Are you sure?
492 yesno 'Are you sure you want to commit?' || return 1
494 # Add the ChangeLog entry
495 old_chlog=`get_unique_file_name "$change_log_dir/ChangeLog.old"`
496 mv "$change_log_dir/ChangeLog" "$old_chlog" || \
497 abort 'Could not backup ChangeLog'
498 trap "echo SIGINT; mv \"$old_chlog\" \"$change_log_dir/ChangeLog\"" SIGINT
499 echo "$chlog_entry" >"$change_log_dir/ChangeLog"
500 echo >>"$change_log_dir/ChangeLog"
501 cat "$old_chlog" >>"$change_log_dir/ChangeLog"
503 # --Commit-- finally! :D
504 $SVN commit "$@" || {
505 mv "$old_chlog" "$change_log_dir/ChangeLog"
506 abort "Commit failed, $SVN returned $?"
509 # In the end, perform an svn up to update externals
510 $SVN update "$change_log_dir"
511 svn_commit_rv=$?
513 # Send the mail
514 mail_file=`get_unique_file_name "$change_log_dir/mail"`
515 echo "\
516 From: $mail_from
517 To: $mail_to
518 Subject: $mail_subject
520 $mail_comment
522 ChangeLog:
523 $chlog_entry
525 $svn_diff_stat
527 $svn_diff" | sed 's/^\.$/ ./' >"$mail_file"
528 # We change lines with only a `.' because they could mean "end-of-mail"
530 test -f ~/.signature && echo '-- ' >>"$mail_file" && \
531 cat ~/.signature >>"$mail_file"
532 yesno "Sign the mail using $GPG ?" && \
533 $GPG --clearsign "$mail_file"
534 test -f "$mail_file.asc" && \
535 mv "$mail_file.asc" "$mail_file"
536 # FIXME: This looks a bit fragile. What if $mail_to = -s foo ? Will it
537 # override the previous -s option?
538 cat "$mail_file" | mail -s "$mail_subject" "$mail_to"
539 rm "$tmp_log"
540 rm "$old_chlog"
541 return $svn_commit_rv
544 # svn_version
545 svn_version()
547 echo "Using svn-wrapper v$version (C) SIGOURE Benoit [GPL]"
548 sed '/^# $Id[:].*$/!d;s/.*$Id[:] *//;s/ *$ *//;s/ \([0-9][0-9]*\)/ (r\1)/' "$0"
551 # has_prop prop-name [path]
552 # return value: 0 -> path has the property prop-name set.
553 # 1 -> path has no property prop-name.
554 # 2 -> svn error.
555 has_prop()
557 hp_plist=`$SVN proplist "$2"`
558 test $? -ne 0 && return 2
559 hp_res=`echo "$hp_plist" | sed "/^ *$1\$/!d"`
560 test x"$hp_res" = x && return 1
561 return 0
564 # svn_propadd prop-name prop-val [path]
565 svn_propadd()
567 test $# -lt 2 \
568 && abort 'Not enough arguments provided; try `svn help propadd` for more info'
569 test $# -gt 3 \
570 && abort 'Too many arguments provided; try `svn help propadd` for more info'
572 path="$3"
573 test x"$path" = x && path='.' && set dummy "$@" '.' && shift
574 has_prop "$1" "$3" || {
575 test $? -eq 2 && return 1 # svn error
576 # no property found:
577 yesno "'$path' has no property named '$1', do you want to add it?" \
578 && $SVN propset "$@"
579 return $?
582 current_prop_val=`$SVN propget "$1" "$3"`
583 test $? -ne 0 && abort "Failed to get the current value of property '$1'."
585 $SVN propset "$1" "$current_prop_val
586 $2" "$3" >/dev/null || abort "Failed to add '$3' in the property '$1'."
588 current_prop_val=`$SVN propget "$1" "$3" || echo "$current_prop_val
589 $2"`
590 echo "property '$1' updated on '$path', new value:
591 $current_prop_val"
594 # svn_propsed prop-name sed-script [path]
595 svn_propsed()
597 test $# -lt 2 \
598 && abort 'Not enough arguments provided; try `svn help propsed` for more info'
599 test $# -gt 3 \
600 && abort 'Too many arguments provided; try `svn help propsed` for more info'
602 path="$3"
603 test x"$path" = x && path='.'
604 has_prop "$1" "$3" || {
605 test $? -eq 2 && return 1 # svn error
606 # no property found:
607 abort "'$path' has no property named '$1'."
610 prop_val=`$SVN propget "$1" "$3"`
611 test $? -ne 0 && abort "Failed to get the current value of property '$1'."
613 prop_val=`echo "$prop_val" | sed "$2"`
614 test $? -ne 0 && abort "Failed to run the sed script '$2'."
616 $SVN propset "$1" "$prop_val" "$3" >/dev/null \
617 || abort "Failed to update the property '$1' with value '$prop_val'."
619 new_prop_val=`$SVN propget "$1" "$3" || echo "$prop_val"`
620 echo "property '$1' updated on '$path', new value:
621 $new_prop_val"
624 # svn_ignore [paths]
625 svn_ignore()
627 if [ $# -eq 0 ]; then # Simply display ignore-list.
628 $SVN propget 'svn:ignore'
629 elif [ $# -eq 1 ]; then
630 if [ -d "$1" ]; then # Display ignore-list for $1
631 $SVN propget 'svn:ignore' "$1"
632 else # Add $1 in ignore-list of `.'.
633 svn_propadd 'svn:ignore' "$1"
635 else # Add arguments in svn:ignore.
636 i=0; last_arg=''
637 while [ $i -lt $# ]; do
638 arg="$1"
639 shift
640 if [ $i -eq $# ]; then
641 last_arg="$arg"
642 else
643 set dummy "$@" "$arg"
644 shift
646 i=`expr $i + 1`
647 done
648 i_files=`echo "$*" | tr -s ' ' '\n'`
649 if [ -d "$last_arg" ]; then # Add in ignore-list of $last_arg
650 svn_propadd 'svn:ignore' "$i_files" "$last_arg"
651 else # Add in ignore-list of `.'
652 svn_propadd 'svn:ignore' "$i_files
653 $last_arg"
658 # svn_help
659 svn_help()
661 if [ $# -eq 0 ]; then
662 svn_version
663 $SVN help
664 rv=$?
665 echo '
666 Additionnal commands provided by svn-wrapper:
667 diffstat (ds)
668 ignore
669 propadd (padd, pa)
670 propsed (psed)
671 revision (rev)
672 touch
673 selfupdate
674 version'
675 return $rv
676 else
677 case $1 in
678 diffstat | ds)
679 echo 'diffstat (ds): Display the histogram from svn diff-output.'
680 $SVN help diff | sed '1d;
681 s/differences*/histogram/;
682 2,35 s/diff/diffstat/g'
684 ignore)
685 echo 'ignore: Add some files in the svn:ignore property.
686 usage: 1. ignore [PATH]
687 2. ignore FILE [FILES...] [PATH]
689 1. Display the value of svn:ignore property on [PATH].
690 2. Add some files in the svn:ignore property of [PATH].
692 If you want to add directories in the ignore-list, be careful:
693 svn ignore foo/ bar/
694 will add "foo/" in the property svn:ignore within the directory bar!
695 Instead use:
696 svn ignore foo/ bar/ .
697 (It'\''s somewhat like with mv)
699 Valid options:
700 None.'
702 propadd | padd | pa)
703 echo 'propadd (padd, pa): Add something in the value of a property.
704 usage: propadd PROPNAME PROPVAL PATH
706 PROPVAL will be appended at the end of the property PROPNAME.
708 Valid options:
709 None.'
711 propsed | psed)
712 echo 'propsed (psed): Edit a property with sed.
713 usage: propsed PROPNAME SED-ARGS PATH
715 eg: svn propsed svn:externals "s/http/https/" .
717 Valid options:
718 None.'
720 revision | rev)
721 echo 'revision (rev): Display the revision number of a local or remote item.'
722 $SVN help info | sed '1d;
723 s/information/revision/g;
724 s/revision about/the revision of/g;
725 2,35 s/info/revision/g;
726 /-xml/d'
728 touch)
729 echo 'touch: Touch a file and svn add it.
730 usage: touch FILE [FILES]...
732 Valid options:
733 None.'
735 selfupdate | self-update)
736 echo 'selfupdate: Attempt to update svn-wrapper.sh
737 usage: selfupdate
739 Valid options:
740 None.'
742 version)
743 echo 'version: Display the version info of svn and svn-wrapper.
744 usage: version
746 Valid options:
747 None.'
749 *) $SVN help "$@";;
750 esac
754 # svn_status [args...]
755 svn_status()
757 $SVN status "$@" | sed "$sed_svn_st_color"
758 return $?
761 # ------------------- #
762 # `main' starts here. #
763 # ------------------- #
765 # Sanity checks.
766 if echo | diffstat >/dev/null 2>/dev/null; then :; else
767 warn 'diffstat is not installed on your system or not in your PATH.'
768 test -f /etc/debian_version \
769 && notice 'you might want to `apt-get install diffstat`.'
771 if echo | mail >/dev/null 2>/dev/null; then :; else
772 if [ $? -gt 100 ]; then
773 warn 'mail is not installed on your system or not in your PATH.'
774 test -f /etc/debian_version \
775 && notice 'you might want to:
776 # apt-get install mailx
777 # dpkg-reconfigure exim'
781 # Define colors if stdout is a tty.
782 if test -t 1; then
783 set_colors
784 else # stdout isn't a tty => don't print colors.
785 set_nocolors
788 # Considere this as a sed function :P.
789 sed_svn_st_color="
790 s/^\(.\)C/\1${lred}C${std}/
791 s/^A/${lgreen}A${std}/; t
792 s/^C/${lred}C${std}/; t
793 s/^D/${lyellow}D${std}/; t
794 s/^I/${purple}I${std}/; t
795 s/^M/${lgreen}M${std}/; t
796 s/^R/${lblue}R${std}/; t
797 s/^X/${lblue}X${std}/; t
798 s/^?/${lred}?${std}/; t
799 s/^!/${lred}!${std}/; t
800 s/^~/${lwhite}~${std}/; t"
802 # For dev:
803 test "x$1" = x--debug && shift && set -x
805 case "$1" in
806 # ------------------------------- #
807 # Hooks for standard SVN commands #
808 # ------------------------------- #
809 commit | ci)
810 shift
811 svn_commit "$@"
813 help | \? | h)
814 shift
815 svn_help "$@"
817 status | stat | st)
818 shift
819 svn_status "$@"
821 # -------------------- #
822 # Custom SVN commands #
823 # -------------------- #
824 diffstat | ds)
825 shift
826 $SVN diff "$@" | diffstat
828 ignore)
829 shift
830 svn_ignore "$@"
832 propadd | padd | pa)
833 shift
834 svn_propadd "$@"
836 propsed | psed)
837 shift
838 svn_propsed "$@"
840 revision | rev)
841 shift
842 $SVN info "$@" | sed '/^Revision/!d;s/^Revision: //'
844 touch)
845 shift
846 touch "$@" && svn add "$@"
848 selfupdate | self-update)
849 shift
850 selfupdate "$@"
852 version | -version | --version)
853 shift
854 set dummy '--version' "$@"
855 shift
856 svn_version
857 exec $SVN "$@"
859 *) exec $SVN "$@"
861 esac