From 04c5e397cfdce1c464c8f69d51129eb1e3049673 Mon Sep 17 00:00:00 2001 From: "Michael A. Smith" Date: Fri, 5 Jun 2026 15:50:02 -0400 Subject: [PATCH 1/3] fix(openemr-cmd): avoid SIGPIPE in worktree validation under pipefail wt_validate_dir and wt_validate_dir_safe piped 'git worktree list --porcelain' into 'grep -Fqx'. Under 'set -o pipefail', grep -q exits on the first match and closes the pipe; git, still writing the remaining entries, takes SIGPIPE and exits 141. pipefail then reports the whole pipeline as failed, so a path that IS a registered worktree is rejected. This only triggers once git's output exceeds the pipe buffer (~64KB), i.e. with many worktrees, which is why it stays latent on typical setups. The symptom is 'worktree list' showing "(no worktrees)" and 'worktree remove' aborting with "is not a registered git worktree". Capture the listing into a variable and match it with a herestring, eliminating the pipe (and the SIGPIPE) entirely. Assisted-by: Claude Code --- utilities/openemr-cmd/openemr-cmd | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/utilities/openemr-cmd/openemr-cmd b/utilities/openemr-cmd/openemr-cmd index 9350ea23..5476f153 100755 --- a/utilities/openemr-cmd/openemr-cmd +++ b/utilities/openemr-cmd/openemr-cmd @@ -18,7 +18,7 @@ set -euo pipefail ################################################################################################# # Increment the version when modify script -VERSION="1.0.39" +VERSION="1.0.40" # ============================================================================ # WORKTREE STATE MANAGEMENT @@ -150,9 +150,14 @@ wt_validate_dir() { wt_die "Worktree path '${dir_real}' is not within expected parent '${worktree_parent_real}'" fi - # 3. Ensure it is a registered git worktree of OPENEMR_ROOT - if ! git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null \ - | grep -Fqx "worktree ${dir_real}"; then + # 3. Ensure it is a registered git worktree of OPENEMR_ROOT. + # Capture the listing first rather than piping into grep: under pipefail, + # 'grep -q' exits on first match and SIGPIPEs git mid-write, which git + # reports as failure (141) once its output exceeds the pipe buffer (many + # worktrees). A herestring avoids the pipe entirely. + local worktrees + worktrees=$(git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null) + if ! grep -Fqx "worktree ${dir_real}" <<< "${worktrees}"; then wt_die "Path '${dir_real}' is not a registered git worktree of '${OPENEMR_ROOT}'" fi } @@ -171,7 +176,9 @@ wt_validate_dir_safe() { return 1 fi - if ! git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null | grep -Fqx "worktree ${dir_real}"; then + local worktrees + worktrees=$(git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null) + if ! grep -Fqx "worktree ${dir_real}" <<< "${worktrees}"; then return 1 fi } From 538e505d2e103730334a665e409967e794ab5506 Mon Sep 17 00:00:00 2001 From: "Michael A. Smith" Date: Fri, 5 Jun 2026 20:32:29 -0400 Subject: [PATCH 2/3] test(openemr-cmd): bump OC_SCRIPT_FUNCS_END after worktree validation fix The pipefail/SIGPIPE fix added 7 net lines above the function-definition boundary, so sourcing head -n 1446 cut mid-function and every pure-helper test failed with "syntax error: unexpected end of file". Move the boundary to 1452, the closing brace of the last function before USAGE_EXIT_CODE. Assisted-by: Claude Code --- tests/bats/openemr-cmd/helpers.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bats/openemr-cmd/helpers.bash b/tests/bats/openemr-cmd/helpers.bash index 945cfde1..1d2ed490 100644 --- a/tests/bats/openemr-cmd/helpers.bash +++ b/tests/bats/openemr-cmd/helpers.bash @@ -62,7 +62,7 @@ STUB # If the script is restructured, bump this constant — the test # 'OC_SCRIPT_FUNCS_END points at end of function defs' in helpers_pure.bats # will fail loudly when it drifts. -OC_SCRIPT_FUNCS_END=1460 +OC_SCRIPT_FUNCS_END=1466 # Source ONLY the function definitions of openemr-cmd into the current shell. # Caller is responsible for setting OPENEMR_ROOT (and WT_STATE_FILE / others From c3ceea1cd54394b1593e60a459f84734c4e4f1ef Mon Sep 17 00:00:00 2001 From: "Michael A. Smith" Date: Fri, 5 Jun 2026 22:14:23 -0400 Subject: [PATCH 3/3] fix(openemr-cmd): preserve error semantics when capturing worktree list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Splitting the 'git worktree list | grep' pipeline into a standalone command substitution changed its set -e behavior: previously git's exit status was masked inside the 'if ! ...' test, but a bare assignment now aborts the script if git fails. Restore the original contract — wt_die with a clear message in the fatal variant, 'return 1' in the safe one — by handling the substitution's exit explicitly. Bump OC_SCRIPT_FUNCS_END for the added continuation line. Assisted-by: Claude Code --- tests/bats/openemr-cmd/helpers.bash | 2 +- utilities/openemr-cmd/openemr-cmd | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/bats/openemr-cmd/helpers.bash b/tests/bats/openemr-cmd/helpers.bash index 1d2ed490..3b094bb5 100644 --- a/tests/bats/openemr-cmd/helpers.bash +++ b/tests/bats/openemr-cmd/helpers.bash @@ -62,7 +62,7 @@ STUB # If the script is restructured, bump this constant — the test # 'OC_SCRIPT_FUNCS_END points at end of function defs' in helpers_pure.bats # will fail loudly when it drifts. -OC_SCRIPT_FUNCS_END=1466 +OC_SCRIPT_FUNCS_END=1467 # Source ONLY the function definitions of openemr-cmd into the current shell. # Caller is responsible for setting OPENEMR_ROOT (and WT_STATE_FILE / others diff --git a/utilities/openemr-cmd/openemr-cmd b/utilities/openemr-cmd/openemr-cmd index 5476f153..0ce52d5f 100755 --- a/utilities/openemr-cmd/openemr-cmd +++ b/utilities/openemr-cmd/openemr-cmd @@ -156,7 +156,8 @@ wt_validate_dir() { # reports as failure (141) once its output exceeds the pipe buffer (many # worktrees). A herestring avoids the pipe entirely. local worktrees - worktrees=$(git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null) + worktrees=$(git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null) \ + || wt_die "Cannot list git worktrees of '${OPENEMR_ROOT}'" if ! grep -Fqx "worktree ${dir_real}" <<< "${worktrees}"; then wt_die "Path '${dir_real}' is not a registered git worktree of '${OPENEMR_ROOT}'" fi @@ -177,7 +178,7 @@ wt_validate_dir_safe() { fi local worktrees - worktrees=$(git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null) + worktrees=$(git -C "${OPENEMR_ROOT}" worktree list --porcelain 2>/dev/null) || return 1 if ! grep -Fqx "worktree ${dir_real}" <<< "${worktrees}"; then return 1 fi