fix: clean goroutine exit in timeout message helpers

Add done channel to runGitCmdWithTimeoutMsg and runCmdWithTimeoutMessage
so goroutines exit immediately when command completes, rather than
waiting for the full timeout duration.

Follow-up to PR #678.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-21 12:43:18 -08:00
parent fd8b987189
commit 169684754d
2 changed files with 10 additions and 2 deletions

View File

@@ -2156,17 +2156,21 @@ func checkOrphanedChildrenInJSONL(jsonlPath string) (*OrphanedChildren, error) {
// runGitCmdWithTimeoutMsg runs a git command and prints a helpful message if it takes too long. // runGitCmdWithTimeoutMsg runs a git command and prints a helpful message if it takes too long.
// This helps when git operations hang waiting for credential/browser auth. // This helps when git operations hang waiting for credential/browser auth.
func runGitCmdWithTimeoutMsg(ctx context.Context, cmd *exec.Cmd, cmdName string, timeoutDelay time.Duration) ([]byte, error) { func runGitCmdWithTimeoutMsg(ctx context.Context, cmd *exec.Cmd, cmdName string, timeoutDelay time.Duration) ([]byte, error) {
// Start a timer to print a message if the command takes too long // Use done channel to cleanly exit goroutine when command completes
done := make(chan struct{})
go func() { go func() {
select { select {
case <-time.After(timeoutDelay): case <-time.After(timeoutDelay):
fmt.Fprintf(os.Stderr, "⏳ %s is taking longer than expected (possibly waiting for authentication). If this hangs, check for a browser auth prompt or run 'git status' in another terminal.\n", cmdName) fmt.Fprintf(os.Stderr, "⏳ %s is taking longer than expected (possibly waiting for authentication). If this hangs, check for a browser auth prompt or run 'git status' in another terminal.\n", cmdName)
case <-done:
// Command completed, exit cleanly
case <-ctx.Done(): case <-ctx.Done():
// Context canceled, don't print message // Context canceled, don't print message
} }
}() }()
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
close(done)
return output, err return output, err
} }

View File

@@ -785,17 +785,21 @@ func fetchAndRebaseInWorktree(ctx context.Context, worktreePath, branch, remote
// //
// Returns: combined output and error from the command // Returns: combined output and error from the command
func runCmdWithTimeoutMessage(ctx context.Context, timeoutMsg string, timeoutDelay time.Duration, cmd *exec.Cmd) ([]byte, error) { func runCmdWithTimeoutMessage(ctx context.Context, timeoutMsg string, timeoutDelay time.Duration, cmd *exec.Cmd) ([]byte, error) {
// Start a timer to print a message if the command takes too long // Use done channel to cleanly exit goroutine when command completes
done := make(chan struct{})
go func() { go func() {
select { select {
case <-time.After(timeoutDelay): case <-time.After(timeoutDelay):
fmt.Fprintf(os.Stderr, "⏳ %s\n", timeoutMsg) fmt.Fprintf(os.Stderr, "⏳ %s\n", timeoutMsg)
case <-done:
// Command completed, exit cleanly
case <-ctx.Done(): case <-ctx.Done():
// Context canceled, don't print message // Context canceled, don't print message
} }
}() }()
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
close(done)
return output, err return output, err
} }