1 # test-lib-functions-tg.sh - test library functions specific to TopGit
2 # Copyright (C) 2017 Kyle J. McKay
6 # The test library itself is expected to set and export TG_TEST_FULL_PATH as
7 # the full path to the current "tg" executable being tested
9 # IMPORTANT: test-lib-functions-tg.sh MUST NOT EXECUTE ANY CODE!
11 # Also since this file is sourced BEFORE test-lib-functions.sh it may not
12 # override any functions in there either
14 # The function test_lib_functions_tg_init, which should ALWAYS be kept as
15 # the very LAST function in this file, will be called once (AFTER
16 # test-lib-functions.sh has been sourced and inited) but before any other
17 # functions in it are called
21 ## TopGit specific test functions
25 # tg_test_include [-C <dir>] [-r <remote>] [-u] [-f]
27 # Source tg in "tg__include=1" mode to provide access to internal functions
28 # Since this bypasses normal tg options parsing provide a few options
30 # While -C <dir> options are indeed parsed and acted upon and the "include"
31 # itself will occur with the result of any -C <dir> options still active,
32 # the directory will be changed back to the saved "$PWD" (saved at the
33 # beginning of this function) immediately after the "include" takes place.
34 # As a result, if any -C <dir> options are used it may subsequently be
35 # necessary to do an explicit cd <dir> later on before calling any of the
36 # internal tg functions.
38 # This function, obviously, causes the "tg" file to be sourced at the current
39 # shell level so there's no "tg_uninclude" possible, but since the various
40 # test_expect/tolerate functions run the test code itself in a subshell by
41 # default, use of tg_test_include from within a test body will be effectively
42 # local for that specific test body and be "undone" after it's finished.
44 # Note that the special "tg__include" variable IS left set to "1" after this
45 # function returns (but it is NOT exported) and all temporary variables used by
46 # this function are unset
48 # Return status will be "0" on success or last failing status (which will be
49 # from the include itself if that's the last thing to fail)
51 # However, if the "-f" option is passed any failure is immediately fatal
53 # Since the test library always sets TG_TEST_FULL_PATH it's a fatal error to
54 # call this function when that's unset or invalid (not a readable file)
56 # Note that the "-u" option causes the base_remote variable to always be unset
57 # immediately after the include while the "-r <remote>" option causes
58 # the base_remote variable to be set before the include; if neither option is
59 # used and the caller has set base_remote, it will end up as the remote since
60 # the "tg" command will keep it; however, if the base_remote variable is either
61 # unset or empty and the "-u" option is not used when this function is called
62 # then any base_remote setting that "tg" itself picks up will be kept
65 [ -f "$TG_TEST_FULL_PATH" ] && [ -r "$TG_TEST_FULL_PATH" ] ||
66 fatal
"tg_test_include called while TG_TEST_FULL_PATH is unset or invalid"
67 unset_ _tgf_noremote _tgf_fatal _tgf_curdir _tgf_errcode
69 while [ $# -gt 0 ]; do case "$1" in
71 unset_ _tgf_noremote _tgf_fatal _tgf_curdir
72 echo "tg_test_include [-C <dir>] [-r <remote>] [-u] [-f]"
77 [ -n "$1" ] || fatal
"tg_test_include option -C requires an argument"
85 [ -n "$1" ] || fatal
"tg_test_include option -r requires an argument"
97 echo "tg_test_include: unknown option: $1" >&2
104 [ $# -eq 0 ] || fatal
"tg_test_include non-option arguments prohibited: $*"
105 unset_ tg__include
# make sure it's not exported
107 # MUST do this AFTER changing the current directory since it sets $git_dir!
109 .
"$TG_TEST_FULL_PATH" || _tgf_errcode
=$?
110 [ -z "$_tgf_noremote" ] || base_remote
=
111 cd "$_tgf_curdir" || _fatal
"tg_test_include post-include cd failed to: $_tgf_curdir"
112 set -- "$_tgf_errcode" "$_tgf_fatal"
113 unset_ _tgf_noremote _tgf_fatal _tgf_curdir _tgf_errcode
114 [ -z "$2" ] ||
[ "$1" = "0" ] || _fatal
"tg_test_include sourcing of tg failed with status $1"
119 # tg_test_setup_topgit [-C <dir>] [-f]
121 tg_test_setup_topgit
() {
122 [ -f "$TG_TEST_FULL_PATH" ] && [ -r "$TG_TEST_FULL_PATH" ] ||
123 fatal
"tg_test_setup_topgit called while TG_TEST_FULL_PATH is unset or invalid"
124 unset_ _tgf_fatal _tgf_curdir _tgf_td
126 while [ $# -gt 0 ]; do case "$1" in
128 unset_ _tgf_fatal _tgf_curdir
129 echo "tg_test_setup_topgit [-C <dir>] [-f]"
134 [ -n "$1" ] || fatal
"tg_test_include option -C requires an argument"
145 echo "tg_test_setup_topgit: unknown option: $1" >&2
152 [ $# -eq 0 ] || fatal
"tg_test_setup_topgit non-option arguments prohibited: $*"
153 _tgf_td
="$(test_get_temp -d setup)" || failt
"tg_test_setup_topgit test_get_temp failed"
154 _tgf_td_script
="$_tgf_td/${TG_TEST_FULL_PATH##*/}"
155 write_script
"$_tgf_td_script" <<-'KLUDGE'
156 # without this $0 will be wrong and the installed hook will never run
158 PATH="${TG_TEST_FULL_PATH%/*}:$PATH" && export PATH &&
159 . "$TG_TEST_FULL_PATH" &&
161 setup_hook "pre-commit"
164 TG_TEST_FULL_PATH
="$TG_TEST_FULL_PATH" "$_tgf_td_script" || _tgf_errcode
=$?
165 cd "$_tgf_curdir" || _fatal
"tg_test_setup_topgit post-setup cd failed to: $_tgf_curdir"
166 set -- "$_tgf_errcode" "$_tgf_fatal"
168 unset_ _tgf_fatal _tgf_curdir _tgf_errcode _tgf_td _tgf_td_script
169 [ -z "$2" ] ||
[ "$1" = "0" ] || _fatal
"tg_test_setup_topgit failed with status $1"
174 # tg_test_v_getbases <varname> [<remotename>]
176 # If tg_test_bases is unset or "" the default for the tg being tested is used.
177 # Otherwise it must be set to "refs" or "heads" or a fatal error will occur.
179 # The variable named by <varname> is set to the full ref prefix for top-bases
180 # (as selected by tg_test_bases). If <remotename> is non-empty it will be the
181 # prefix for top-bases under that remote's ref namespace.
183 # Example return values:
185 # tg_test_v_getbases x # x='refs/top-bases' # "refs"
186 # tg_test_v_getbases x # x='refs/heads/{top-bases}' # "heads"
187 # tg_test_v_getbases x origin # x='refs/remotes/origin/top-bases' # "refs"
188 # tg_test_v_getbases x origin # x='refs/remotes/origin/{top-bases}' # "heads"
190 tg_test_v_getbases
() {
191 [ -n "$1" ] || fatal
"tg_test_v_getbases called without varname argument"
192 [ $# -le 2 ] || fatal
"tg_test_v_getbases called with more than two arguments"
193 case "${tg_test_bases:-$tg__top_bases}" in
194 "refs") _tgbases
="top-bases";;
195 "heads") _tgbases
="heads/{top-bases}";;
196 *) fatal
"tg_test_v_getbases called with invalid tg_test_bases setting \"$tg_test_bases\"";;
199 set -- "$1" "refs/remotes/$2/${_tgbases#heads/}"
201 set -- "$1" "refs/$_tgbases"
208 # tg_test_v_getremote <varname> [<remotename>]
210 # Set the variable named by <varname> to <remotename> unless <remotename> is
211 # omitted or empty in which case use the value of tg_test_remote unless it's
212 # empty in which case fail with a fatal error.
214 tg_test_v_getremote
() {
215 [ -n "$1" ] || fatal
"tg_test_getremote called without varname argument"
216 [ $# -le 2 ] || fatal
"tg_test_getremote called with more than two arguments"
217 [ -n "${2:-$tg_test_remote}" ] ||
218 fatal
"tg_test_getremote called with no remote name argument and \$tg_test_remote not set"
219 eval "$1"'="${2:-$tg_test_remote}"'
223 # tg_test_bare_tree [-C <dir>] <treeish>
225 # Output the hash of the tree that's equivalent to <treeish>'s tree with any
226 # .topdeps and .topmsg files removed, If <treeish> does not have any top-level
227 # .topdeps or .topmsg files then the result will be the same as <treeish>^{tree}
228 tg_test_bare_tree
() {
230 [ $# -lt 2 ] ||
[ "$1" != "-C" ] ||
{ shift; _tct_dir
="${1:-.}"; shift; }
231 [ -d "$_tct_dir" ] ||
232 fatal
"tg_test_bare_tree no such directory \"$_tct_dir\""
233 [ $# -eq 1 ] && [ -n "$1" ] ||
234 fatal
"tg_test_bare_tree missing treeish argument"
235 set -- "$_tct_dir" "$1"
237 git
-C "$1" ls-tree
--full-tree "$2^{tree}" |
238 # The first character after the '/' in the sed pattern is a literal tab
239 sed -e '/ \.topdeps$/d' -e '/ \.topmsg$/d' |
244 # tg_test_create_branch [-C <dir>] [--notick] [+][\][[<remote>]:[:]]<branch> [--no-topmsg] [-m "message"] [:[:[:]][~]]<start> [<dep>...]
246 # Create a new TopGit branch named <branch> in the current repository (or
249 # Unless --notick is used the test_tick function will be called just prior to
250 # the creation of each new commit.
252 # All of the new ref names to be created must be non-existent unless the "+"
253 # prefix is used and then they're just overwritten if they exist. A leading
254 # "\" will be stripped so branch names starting with "+" can be used without
255 # needing to use the overwrite option.
257 # tg_test_v_getbases is used so tg_test_bases must be unset or "refs" or "heads".
259 # If [-m "message"] is omitted the message will be "branch <branch>" and
260 # the same with "[PATCH] " prepended for .topmsg (unless it's a bare branch).
261 # A "[PATCH] " value will be prepended to any -m value when creating the
262 # .topmsg file unless "message" starts with a "[" character. However, with
263 # --no-topmsg the .topmsg file is omitted entirely just like a bare branch, but
264 # it's still possible to have a .topdeps file in this case (the message will
265 # still be used for the commit message if given).
267 # The branch will start from <start> which must be the name of a ref located
268 # under refs/heads i.e. refs/heads/<start>. <start> will become the first
269 # dependency in the .topdeps file. Any additional <dep> names must also be
270 # Git branch names and will be listed in the order given as additional lines
271 # in the .topdeps file.
273 # If <start> begins with one ":" it may be any committish AND it will be
274 # omitted from the .topdeps file so the .topdeps file will then be empty
275 # unless at least one [<dep>...] is given.
277 # If <start> begins with ":~" it may be any committish AND the .topdeps file
278 # will be omitted entirely just like a bare branch, but it's still possible to
279 # have a .topmsg file in this case.
281 # If <start> begins with two colons "::" it may be any committish, but
282 # [<dep>...] MUST BE OMITTED and the created TopGit branch will be bare
283 # (i.e. it will have neither a .topmsg nor a .topdeps file at all). This is
284 # really just a convenience shortcut to save typing because the same thing can
285 # be accomplished with --no-topmsg and :~<start> instead.
287 # If <start> begins with three colons ":::" it may be any committish, but
288 # [<dep>...] MUST BE OMITTED and the created branch will not have any
289 # corresponding base(s) and will be bare (i.e. it will be a non-TopGit branch)
290 # and will have a single file added in the style of the test_commit function
291 # where the tag will be omitted if the message contains whitespace or any other
292 # invalid ref name characters.
294 # Additionally if <start> begins with a colon (or two or three) it may be the
295 # empty string to start from a new empty tree root commit.
297 # If <remote>:<branch> is used a remote TopGit branch will be created instead
298 # in which case the :<start> form may be most useful as it can be used to
299 # specify a starting point not under refs/heads.
301 # If <remote>::<branch> is used then both a local and remote branch will be
302 # created (both with the same branch and base values).
304 # If <remote> is empty (but the trailing colon is still present) the value of
305 # the tg_test_remote variable will be used for the remote name (in which case
306 # if tg_test_remote is empty a fatal error will occur).
308 # The current working tree, index and symolic-ref setting of HEAD are left
309 # completely untouched by this function although if HEAD is a symbolic ref to
310 # <branch> and <branch> is unborn, it WILL be created by this function which
311 # will impact Git's view of the working tree and index in that case.
313 # Note that NO CHECKING is done on the <dep> values whatsoever! They're just
314 # dumped into the .topdeps file as-is if given.
316 tg_test_create_branch
() {
318 [ $# -lt 2 ] ||
[ "$1" != "-C" ] ||
{ shift; _tcb_dir
="${1:-.}"; shift; }
319 [ -d "$_tcb_dir" ] ||
320 fatal
"tg_test_create_branch: no such directory \"$_tcb_dir\""
322 [ "$1" != "--notick" ] ||
{ _tcb_nto
="$1"; shift; }
323 [ $# -ge 1 ] && [ -n "$1" ] ||
324 fatal
"tg_test_create_branch: missing <branch> name to create"
332 case "$_tcb_new" in "+"*)
333 _tcb_new
="${_tcb_new#?}"
336 case "$_tcb_new" in "\\"*) _tcb_new
="${_tcb_new#?}"; esac
339 _tcb_rmt
="${_tcb_new%%::*}"
340 tg_test_v_getremote _tcb_rmt
"$_tcb_rmt"
341 _tcb_new
="${_tcb_new#*::}"
344 _tcb_rmt
="${_tcb_new%%:*}"
345 tg_test_v_getremote _tcb_rmt
"$_tcb_rmt"
346 _tcb_new
="${_tcb_new#*:}"
350 [ -n "$_tcb_new" ] ||
351 fatal
"tg_test_create_branch: invalid empty <branch> name"
352 [ -n "$_tcb_rmtonly" ] || tg_test_v_getbases _tcb_bases
353 [ -z "$_tcb_rmt" ] || tg_test_v_getbases _tcb_rmtbases
"$_tcb_rmt"
355 [ "$1" != "--no-topmsg" ] ||
{ shift; _tcb_notm
=1; }
357 [ $# -lt 2 ] ||
[ "$1" != "-m" ] ||
{ shift; _tcb_msg
="$1"; shift; }
358 [ -n "$_tcb_msg" ] || _tcb_msg
="branch $_tcb_new"
359 [ $# -ge 1 ] && [ -n "$1" ] ||
360 fatal
"tg_test_create_branch: missing <start> point argument"
365 _tcb_sdep
="$_tcb_start"
366 _tcb_vref
="refs/heads/$_tcb_start"
367 case "$_tcb_start" in
370 _tcb_vref
="${_tcb_start#:::}"
371 _tcb_vref
="${_tcb_vref#~}"
378 _tcb_vref
="${_tcb_start#::}"
379 _tcb_vref
="${_tcb_vref#~}"
385 _tcb_vref
="${_tcb_start#:~}"
390 _tcb_vref
="${_tcb_start#:}"
393 if [ -z "$_tcb_sdep$_tcb_vref$_tcb_plain" ]; then
394 _tcb_btr
="$(git -C "$_tcb_dir" mktree </dev/null)" ||
395 fatal
"tg_test_create_branch: git mktree failed making empty tree"
396 [ -n "$_tcb_nto" ] || test_tick
397 _tcb_vref
="$(git -C "$_tcb_dir" commit-tree </dev/null \
398 -m "tg_test_create_branch
$_tcb_new root
" "$_tcb_btr")" && [ -n "$_tcb_vref" ] ||
399 fatal
"tg_test_create_branch: git commit-tree failed committing new root"
402 if [ -n "$_tcb_vref" ]; then
403 _tcb_scmt
="$(git -C "$_tcb_dir" rev-parse --quiet --verify "$_tcb_vref^
0" --)" && [ -n "$_tcb_scmt" ] ||
404 fatal
"tg_test_create_branch: invalid starting point \"$_tcb_vref\""
406 [ $# -eq 0 ] ||
[ -z "$_tcb_notd" ] ||
407 fatal
"tg_test_create_branch: no <dep> arguments allowed for $(b=${_tcb_notm:+bare}&&echo ${b:-non-topdeps}) branch"
408 if [ -n "$_tcb_nooverwrite" ]; then
410 [ -n "$_tcb_rmtonly" ] ||
411 printf '%s\n' "verify refs/heads/$_tcb_new" "verify $_tcb_bases/$_tcb_new"
412 [ -z "$_tcb_rmt" ] ||
413 printf '%s\n' "verify refs/remotes/$_tcb_rmt/$_tcb_new" "verify $_tcb_rmtbases/$_tcb_new"
414 } | git
-C "$_tcb_dir" update-ref
--stdin ||
415 fatal
"tg_test_create_branch: branch \"$_tcb_new\" already exists"
417 if [ -z "$_tcb_plain" ]; then
418 _tcb_btr
="$(tg_test_bare_tree -C "$_tcb_dir" "$_tcb_scmt")" && [ -n "$_tcb_btr" ] ||
419 fatal
"tg_test_create_branch: tg_test_bare_tree failed on \"$_tcb_scmt\" ($_tcb_vref^0)"
420 if [ "$_tcb_btr" != "$(git -C "$_tcb_dir" rev-parse --quiet --verify "$_tcb_scmt^
{tree
}" --)" ]; then
421 [ -n "$_tcb_nto" ] || test_tick
422 _tcb_scmt
="$(git -C "$_tcb_dir" commit-tree </dev/null -p "$_tcb_scmt" \
423 -m "tg_test_create_branch
$_tcb_new base
" "$_tcb_btr")" && [ -n "$_tcb_scmt" ] ||
424 fatal
"tg_test_create_branch: git commit-tree failed"
427 _tcb_hcmt
="$_tcb_scmt"
428 if [ z
"$_tcb_notd$_tcb_notm" != z
"11" ]; then
429 [ -z "$_tcb_sdep" ] ||
set -- "$_tcb_sdep" "$@"
431 [ $# -eq 0 ] || _tcb_fmt
='%s\n'
433 [ -n "$_tcb_notd" ] ||
{
434 _tcb_dps
="$(printf "$_tcb_fmt" "$@
" | git -C "$_tcb_dir" hash-object -t blob -w --stdin)" && [ -n "$_tcb_dps" ] ||
435 fatal
"tg_test_create_branch: git hash-object failed creating .topdeps blob"
438 if [ -z "$_tcb_notm" ]; then
440 "["*) _tcb_sbj
="Subject: $_tcb_msg";;
441 *) _tcb_sbj
="Subject: [PATCH] $_tcb_msg";;
443 _tcb_tms
="$(printf '%s\n' "From
: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>" "$_tcb_sbj" |
444 git -C "$_tcb_dir" hash-object -t blob -w --stdin)" && [ -n "$_tcb_tms" ] ||
445 fatal
"tg_test_create_branch: git hash-object failed creating .topmsg blob"
448 git -C "$_tcb_dir" ls-tree --full-tree "$_tcb_hcmt^
{tree
}" &&
449 printf '100644 blob %s\011%s\n' $_tcb_dps ${_tcb_dps:+.topdeps} $_tcb_tms ${_tcb_tms:+.topmsg}
450 } | git -C "$_tcb_dir" mktree)" && [ -n "$_tcb_htr" ] ||
451 fatal
"tg_test_create_branch: git mktree failed creating new branch \"$_tcb_new\" tree"
452 [ -n "$_tcb_nto" ] || test_tick
453 _tcb_hcmt
="$(git -C "$_tcb_dir" commit-tree </dev/null -p "$_tcb_hcmt" -m "$_tcb_msg" "$_tcb_htr")" && [ -n "$_tcb_hcmt" ] ||
454 fatal
"tg_test_create_branch: git commit-tree failed"
455 elif [ -n "$_tcb_plain" ]; then
456 read -r _tcb_fnm
<<-EOT
459 _tcb_blb
="$(printf '%s\n' "$_tcb_msg" | git -C "$_tcb_dir" hash-object -t blob -w --stdin)" && [ -n "$_tcb_blb" ] ||
460 fatal
"tg_test_create_branch: git hash-object failed creating file \"$_tcb_fnm.t\" blob"
462 [ -z "$_tcb_hcmt" ] || git -C "$_tcb_dir" ls-tree --full-tree "$_tcb_hcmt^
{tree
}"
463 printf '100644 blob %s\011%s\n' "$_tcb_blb" "$_tcb_fnm.t
"
464 } | git -C "$_tcb_dir" mktree)" && [ -n "$_tcb_htr" ] ||
465 fatal
"tg_test_create_branch: git mktree failed creating new plain branch \"$_tcb_new\" tree"
466 [ -n "$_tcb_nto" ] || test_tick
467 _tcb_hcmt
="$(git -C "$_tcb_dir" commit-tree </dev/null ${_tcb_hcmt:+-p} $_tcb_hcmt -m "$_tcb_msg" "$_tcb_htr")" && [ -n "$_tcb_hcmt" ] ||
468 fatal
"tg_test_create_branch: git commit-tree failed"
469 ! test_check_one_tag_
$_tcb_msg || git
-C "$_tcb_dir" tag
$_tcb_msg "$_tcb_hcmt"
471 set -- "$_tcb_dir" "$_tcb_new" "$_tcb_overwrite"
472 if [ -n "$_tcb_rmt" ]; then
473 [ -n "$_tcb_plain" ] ||
set -- "$@" "$_tcb_rmtbases/$_tcb_new" "$_tcb_scmt"
474 set -- "$@" "refs/remotes/$_tcb_rmt/$_tcb_new" "$_tcb_hcmt"
476 if [ -z "$_tcb_rmtonly" ]; then
477 [ -n "$_tcb_plain" ] ||
set -- "$@" "$_tcb_bases/$_tcb_new" "$_tcb_scmt"
478 set -- "$@" "refs/heads/$_tcb_new" "$_tcb_hcmt"
480 unset_ _tcb_dir _tcb_nto _tcb_new _tcb_bases _tcb_rmt _tcb_rmtonly _tcb_rmtbases _tcb_msg \
481 _tcb_start _tcb_notd _tcb_sdep _tcb_vref _tcb_scmt _tcb_btr _tcb_hcmt _tcb_fmt _tcb_dps \
482 _tcb_tms _tcb_htr _tcb_notm _tcb_nooverwrite ||
:
483 (_ovwno
="${3:+ }" && shift 3 && printf "update %s %s$_ovwno"'\n' "$@") | git
-C "$1" update-ref
--stdin ||
484 fatal
"tg_test_create_branch: update-ref for branch \"$2\" failed"
488 # tg_test_create_branches [-C <dirpath>] [--notick]
490 # Read `tg_branch_create` instructions from standard input and then call
491 # tg_create_branch for each set of instructions.
493 # Standard input must be a sequence of line groups each consisting of two or
494 # more non-empty lines where the groups are separated by a single blank line.
495 # Each line group must have this form:
497 # [+][\][[<remote>]:[:]]<branch> [--no-topmsg] [optional] [message] [here]
498 # [[delete]:[:[:]][~]]<start>
503 # Note that any <dep> lines must not be empty. If there are no <dep>s, then
504 # there must be no <dep> lines at all.
506 # See the description of tg_test_create_branch for the meaning of the
507 # arguments. The provided <dirpath> and --notick options are passed along
508 # on each call to the tg_test_create_branch function.
510 # Interpretation of "delete:" lines is handled here. No message or deps
511 # are allowed. If <start> is non-empty, all refs (1, 2 or 4) to be deleted
512 # must have that value. If the "+" is NOT present and <start> is empty, all
513 # refs to be deleted MUST actually exist.
515 # Since each line group represents a call to tg_test_create_branch, later
516 # groups may use any branch name created by an earlier group as a <start>
517 # point without problem.
519 tg_test_create_branches
() {
521 [ $# -lt 2 ] ||
[ "$1" != "-C" ] ||
{ shift; _tcbs_dir
="${1:-.}"; shift; }
522 [ -d "$_tcbs_dir" ] ||
523 fatal
"tg_test_create_branches: no such directory \"$_tcbs_dir\""
525 [ "$1" != "--notick" ] ||
{ _tcbs_nto
="$1"; shift; }
527 fatal
"tg_test_create_branches: invalid extra arguments: $*"
533 _tcbs_glno
="$_tcbs_lno"
535 [ -n "$_tcbs_nto" ] || _tcbs_tick
="$(test_get_temp test_tick)"
536 while read -r _tcbs_bname _tcbs_bmsg
&& [ -n "$_tcbs_bname" ]; do
537 _tcbs_lno
="$(( $_tcbs_lno + 1 ))"
538 read -r _tcbs_strt
&& [ -n "$_tcbs_strt" ] ||
539 fatal
"tg_test_create_branches: missing <start> at stdin line $_tcbs_lno"
540 _tcbs_lno
="$(( $_tcbs_lno + 1 ))"
542 case "$_tcbs_bmsg" in "--no-topmsg"|
"--no-topmsg "*)
543 _tcbs_dntm
="--no-topmsg"
544 _tcbs_bmsg
="${_tcbs_bmsg#--no-topmsg}"
545 _tcbs_bmsg
="${_tcbs_bmsg# }"
547 set -- "-C" "$_tcbs_dir" $_tcbs_nto "$_tcbs_bname" $_tcbs_dntm "-m" "$_tcbs_bmsg" "$_tcbs_strt"
549 while read -r _tcbs_dep
&& [ -n "$_tcbs_dep" ]; do
550 _tcbs_lno
="$(( $_tcbs_lno + 1 ))"
551 set -- "$@" "$_tcbs_dep"
554 _tcbs_lno
="$(( $_tcbs_lno + 1 ))"
555 case "$_tcbs_strt" in
557 [ -z "$_tcbs_bmsg" ] ||
558 fatal
"tg_test_create_branches: \"delete:...\" usage prohibits msg at stdin line $_tcbs_glno"
559 [ -n "$_tcbs_nod" ] ||
560 fatal
"tg_test_create_branches: \"delete:...\" usage prohibits deps at stdin line $_tcbs_glno"
562 case "$_tcbs_strt" in
564 _tcbs_strt
="${_tcbs_strt#delete:::}"
567 _tcbs_strt
="${_tcbs_strt#delete::}"
571 _tcbs_strt
="${_tcbs_strt#delete:}"
580 case "$_tcbs_bname" in "+"*)
581 _tcbs_bname
="${_tcbs_bname#?}"
584 case "$_tcbs_bname" in "\\"*) _tcbs_bname
="${_tcbs_bname#?}"; esac
585 case "$_tcbs_bname" in
587 _tcbs_rmt
="${_tcbs_bname%%::*}"
588 tg_test_v_getremote _tcbs_rmt
"$_tcbs_rmt"
589 _tcbs_bname
="${_tcbs_bname#*::}"
592 _tcbs_rmt
="${_tcbs_bname%%:*}"
593 tg_test_v_getremote _tcbs_rmt
"$_tcbs_rmt"
594 _tcbs_bname
="${_tcbs_bname#*:}"
598 [ -n "$_tcbs_bname" ] ||
599 fatal
"tg_test_create_branches: invalid empty delete: <branch> name"
600 if [ -n "$_tcbs_rbs" ]; then
601 [ -n "$_tcbs_rmtonly" ] || tg_test_v_getbases _tcbs_bases
602 [ -z "$_tcbs_rmt" ] || tg_test_v_getbases _tcbs_rmtbases
"$_tcbs_rmt"
605 _tcbs_fmt
='delete %s %s\n'
606 [ -n "$_tcbs_strt" ] ||
[ -n "$_tcbs_mustexist" ] || _tcbs_fmt
='delete %s\n'
607 if [ -n "$_tcbs_rmt" ]; then
608 if [ -n "$_tcbs_rbs" ]; then
609 set -- "$@" "$_tcbs_rmtbases/$_tcb_bname"
610 [ -z "$_tcbs_strt" ] && [ -z "$_tcbs_mustexist" ] ||
611 set -- "$@" "${_tcbs_strt:-$_tcbs_rmtbases/$_tcb_bname}"
613 set -- "$@" "refs/remotes/$_tcbs_rmt/$_tcbs_bname"
614 [ -z "$_tcbs_strt" ] && [ -z "$_tcbs_mustexist" ] ||
615 set -- "$@" "${_tcbs_strt:-refs/remotes/$_tcbs_rmt/$_tcbs_bname}"
617 if [ -z "$_tcbs_rmtonly" ]; then
618 if [ -n "$_tcbs_rbs" ]; then
619 set -- "$@" "$_tcbs_bases/$_tcbs_bname"
620 [ -z "$_tcbs_strt" ] && [ -z "$_tcbs_mustexist" ] ||
621 set -- "$@" "${_tcbs_strt:-$_tcbs_bases/$_tcbs_bname}"
623 set -- "$@" "refs/heads/$_tcbs_bname"
624 [ -z "$_tcbs_strt" ] && [ -z "$_tcbs_mustexist" ] ||
625 set -- "$@" "${_tcbs_strt:-refs/heads/$_tcbs_bname}"
627 printf "$_tcbs_fmt" "$@" | git
-C "$_tcbs_dir" update-ref
--stdin ||
628 fatal
"tg_test_create_branches: failed deleting branch \"$_tcbs_bname\" group at stdin line $_tcbs_glno"
631 (tg_test_create_branch
"$@" && { [ -z "$_tcbs_tick" ] ||
echo "$test_tick" >"$_tcbs_tick"; } ) ||
632 fatal
"tg_test_create_branches: failed creating branch \"$_tcbs_bname\" group at stdin line $_tcbs_glno"
633 [ -z "$_tcbs_tick" ] ||
{ read -r test_tick
<"$_tcbs_tick" ||
:; rm "$_tcbs_tick"; }
636 _tcbs_glno
="$_tcbs_lno"
638 [ -z "$_tcbs_tick" ] ||
! [ -e "$_tcbs_tick" ] ||
rm "$_tcbs_tick"
639 unset_ _tcbs_dir _tcbs_nto _tcbs_name _tcbs_bmsg _tcbs_bstrt _tcbs_lno \
640 _tcbs_dep _tcbs_glno _tcbs_tick _tcbs_nod _tcbs_rbs _tcbs_fmt _tcbs_dntm \
641 _tcbs_bases _tcbs_rmt _tcbs_rmtonly _tcbs_rmtbases _tcbs_mustexist ||
:
646 # tg_test_create_tag [-C <dirpath>] [--notick] [-t] <newtag> [<for-each-ref-pat>...]
648 # If no for-each-ref patterns are given then refs/heads, refs/top-bases and
649 # refs/remotes are used. Only refs that have type `commit` will be put in
650 # the tag. The result will be a new annotated tag <newtag> that can be used
651 # as a source for `tg revert` (and therefore the `tg -w` option too).
653 # The for-each-ref-pat arguments are passed directly to `git for-each-ref`
654 # and may therefore use all wildcard features available with that command.
656 # Unlike ordinary `tg tag` tags, the resulting tags tag the empty blob (or with
657 # -t the empty tree) and there is no consolidation commit made at all, ever.
659 tg_test_create_tag
() {
661 [ $# -lt 2 ] ||
[ "$1" != "-C" ] ||
{ shift; _tct_dir
="${1:-.}"; shift; }
662 [ -d "$_tct_dir" ] ||
663 fatal
"tg_test_create_tag: no such directory \"$_tct_dir\""
665 [ "$1" != "--notick" ] ||
{ _tct_nto
="$1"; shift; }
667 [ "$1" != "-t" ] ||
{ _tct_obj
="tree"; shift; }
669 fatal
"tg_test_create_tag: missing tag name argument"
670 _tct_tname
="$1" && shift
671 _tct_refs
="$(test_get_temp tagrefs)"
672 [ $# -gt 0 ] ||
set -- "refs/heads" "refs/remotes" "refs/top-bases"
673 git
-C "$_tct_dir" for-each-ref
--format="%(objecttype) %(objectname) %(refname)" "$@" |
674 sed -n 's/^commit //p' >"$_tct_refs"
675 _tct_mt
="$(git -C "$_tct_dir" hash-object --stdin -t "$_tct_obj" -w </dev/null)"
676 [ -n "$_tct_nto" ] || test_tick
677 _tct_id
="$(git var GIT_COMMITTER_IDENT)"
678 [ $
(wc -l <"$_tct_refs") -gt 0 ] ||
return 1
686 "-----BEGIN TOPGIT REFS-----
"
687 cat "$_tct_refs" && printf '%s\n' \
688 "-----END TOPGIT REFS-----
"
689 } | git -C "$_tct_dir" hash-object --stdin -t tag -w)" ||
return 1
691 git update-ref
"refs/tags/$_tct_tname" "$_tct_tag" "" ||
return 1
692 unset_ _tct_dir _tct_nto _tct_obj _tct_tname _tct_refs _tct_mt _tct_id _tct_tag
698 ## TopGit specific test functions "init" function
703 # THIS SHOULD ALWAYS BE THE LAST FUNCTION DEFINED IN THIS FILE
705 # Any client that sources this file should immediately call this function
708 # THERE SHOULD NOT BE ANY DIRECTLY EXECUTED LINES OF CODE IN THIS FILE
710 test_lib_functions_tg_init
() {
711 # Nothing to do here yet, but a function must have at least one command