shithub: git9

Download patch

ref: 24677b0d857051fc2a952c1dbceaeefa540d89d6
parent: 57d8a0bd95309bcc221850b263acdccc4e81b6ea
author: kvik <kvik@a-b.xyz>
date: Wed Apr 8 12:53:13 EDT 2020

Introduce text substitution helper subst(1)
Using naive string concatenation to build sed substitution
commands causes problems when the variable text being
pasted contains embedded separator characters. Consider:

	; prefix='/path/user@host'
	; sed 's@^'$prefix'@@':
	sed: @: command garbled: s@^/path/user@host@@:

To fix and avoid such problems we introduce subst(1), a helper
utility working reliably with any regular expression and
substitute text arguments, as well as providing some
convenience.  The above sed command becomes:

	; subst '^'$prefix


--- a/clone
+++ b/clone
@@ -71,7 +71,7 @@
 		git/fs
 		@ {builtin cd $tree && tar cif /fd/1 .} | @ {tar xf /fd/0} \
 			|| die 'checkout failed:' $status
-		for(f in `$nl{walk -f $tree | sed 's@^'$tree'/*@@'}){
+		for(f in `$nl{walk -f $tree | subst '^'$tree'/*'}){
 			if(! ~ $#f 0){
 				idx=.git/index9/tracked/$f
 				mkdir -p `$nl{basename -d $idx}
--- a/common.rc
+++ b/common.rc
@@ -11,11 +11,30 @@
 	exit 'usage'
 }
 
+# subst [-g] this [that]
+fn subst{
+	awk 'BEGIN{
+		global = 0
+		for(i = 1; ARGV[i] ~ /^-/; i++){
+			if(ARGV[i] == "-g")
+				global = 1
+			ARGC--
+		}
+		this = ARGV[i++]; ARGC--
+		that = ARGV[i++]; ARGC--
+	}
+	{
+		if(global) gsub(this, that)
+		else sub(this, that)
+		print
+	}' $*
+}
+
 fn gitup{
 	gitroot=`{git/conf -r >[2]/dev/null}
 	if(~ $#gitroot 0)
 		die 'not a git repository'
-	gitrel=`{pwd | sed 's@^'$gitroot'/*@@'}
+	gitrel=`{pwd | subst '^'$"gitroot'/?'}
 	if(~ $#gitrel 0)
 		gitrel='.'
 	cd $gitroot
--- a/merge
+++ b/merge
@@ -12,7 +12,7 @@
 	theirbr=$3/tree
 
 	all=`{walk -f $ourbr $basebr $theirbr | \
-		 sed 's@^('$ourbr'|'$basebr'|'$theirbr')/*@@g' | sort | uniq}
+		subst -g '^('$ourbr'|'$basebr'|'$theirbr')/*' | sort | uniq}
 	for(f in $all){
 		ours=$ourbr/$f
 		base=$basebr/$f
--- a/pull
+++ b/pull
@@ -74,7 +74,7 @@
 	exit
 
 local=`{git/branch}
-remote=`{git/branch | sed 's@^(refs/)?heads@remotes/'$upstream'@'}
+remote=`{git/branch | subst '^(refs/)?heads' 'remotes/'$upstream}
 
 # we have local commits, but the remote hasn't changed.
 # in this case, we want to keep the local commits untouched.
--- a/push
+++ b/push
@@ -52,7 +52,7 @@
 updates=`$nl{git/send $force $branch $remove $remote || die $status}
 for(ln in $updates){
 	u=`{echo $ln}
-	refpath=`{echo $u(2) | sed 's@^refs/heads/@.git/refs/remotes/'$upstream'/@g'}
+	refpath=`{echo $u(2) | subst '^refs/heads/' '.git/refs/remotes/'$upstream'/'}
 	switch($u(1)){
 	case update;
 		mkdir -p `{basename -d $refpath}