#!/bin/sh # svn wrapper to improve the official command-line client. # # With Subversion 1.6 and below, avoid "svn: Write error: Broken pipe" # error messages when piping the svn output to some command. This is a # workaround to the following bug (fixed in Subversion 1.7): # # http://subversion.tigris.org/issues/show_bug.cgi?id=3014 # # Note: the svnwrapper:term trick prevents this script from freezing # if svn starts a background process via $SVN_SSH (e.g. ssh -fMN ... # for connection sharing) that still has its stderr connected to the # pipe after svn terminates. # # This version supports lines sent to stderr not terminated with a # newline character, such as prompts. Prompts should be sent to the # terminal instead of stderr, but svn is buggy: # # http://subversion.tigris.org/issues/show_bug.cgi?id=1117 # # Bug: zsh sometimes exits with exit status 141 while there hasn't been # a broken pipe, e.g.: # # prunille:~/wd> up # U db/bugs/debian.xml # Updated to revision 42990. # zsh: exit 141 # prunille:~/wd[PIPE]> # # where "up" is a zsh function that does # # svnwrapper up "$@" # # after a test. This happens under both GNU/Linux and Mac OS X. # # With Subversion 1.7 and above, do standard path resolution on arguments # that look like real pathnames (the file itself doesn't need to exist in # case it will be added by svn, but the directory part must exist). # # Script written by Vincent Lefevre in 2010-08 for # the "Broken pipe" filter part, and in 2012-06 for the path resolution # part; released in the public domain. # Use the -f zsh option so that the .zshenv file is not sourced, # in order to make sure that the environment under which svn is # run (in particular $SVN_SSH) is unchanged. [ -n "$ZSH_VERSION" ] || exec zsh -f -- "$0" ${1+"$@"} filter() { unset brpipe while true do unset line timeout while read -r $timeout -k -u 0 ch do line="$line$ch" [[ $ch == $'\012' ]] && break timeout=(-t 0.1) done case $line in svnwrapper:term$'\012') break ;; *Broken\ pipe$'\012') brpipe=1 ;; ?*) printf "%s" "$line" >&2 ;; *) break ;; # empty line (end of file) - parent has died? esac done # The "sleep 5" is there to avoid a rare race condition (it occurred # once): make sure the parent process receives the PIPE signal before # the filter process terminates (which can yield a SIGPIPE in svn). [[ -z $brpipe ]] || { kill -PIPE $$; sleep 5 } } if [[ `svn --version 2> /dev/null` == *version\ 1.[0-6].* ]] then # The "Broken pipe" problem was fixed in Subversion 1.7. { svn "$@"; st=$?; echo "svnwrapper:term" >&2 } 2>>(filter) exit $st fi if [[ $# -ge 1 ]] then # With Subversion 1.7 and later, let's do standard path resolution... for i in {1..$#} do a=$argv[$i] # Skip the following arguments: # * options (arguments that start with a "-"); # * arguments without a "/" (no directory components); # * arguments that seem to have a peg revision. [[ "$a" == [^-]*/* ]] || continue [[ "$a" == *@?* ]] && continue a=${a%@} dir="${a%/*}" [[ -d "$dir" ]] || continue rp=$(realpath "$dir") [[ "$dir" == /* ]] || dir="$PWD/$dir" [[ "$rp" == "$dir" ]] && continue a="$rp/${a##*/}" [[ "$a" == *@* ]] && a="$a@" argv[$i]="$a" done fi svn "$@" # local variables: # mode: sh # eval: (sh-set-shell "zsh") # end: # # $Id: svnwrapper.zsh 113558 2018-11-28 13:26:35Z vinc17/cventin $