fix: Handle platform specific PTY polling for terminal copy (#279)

* fix: Handle platform specific PTY polling for terminal copy

* fix: Code review fixes

* fix: Code review fixes
This commit is contained in:
Abhisek Datta
2026-05-28 18:11:11 +05:30
committed by GitHub
parent 1c25395d74
commit 4540dafccc
6 changed files with 269 additions and 6 deletions
+27 -6
View File
@@ -7,7 +7,7 @@ import (
"os"
"os/exec"
"strings"
"sync"
"time"
"github.com/safedep/dry/log"
"github.com/safedep/dry/usefulerror"
@@ -27,6 +27,10 @@ const (
ExecutionModeAuto
)
// outputDrainGrace bounds how long we wait for the PTY output reader to finish
// after the child exits before forcing it to stop.
const outputDrainGrace = 2 * time.Second
type ExecuteOptions struct {
PackageManagerName string
DryRun bool
@@ -167,12 +171,20 @@ func runPTY(
return fmt.Errorf("failed to create output router: %w", err)
}
var wg sync.WaitGroup
wg.Go(func() {
if _, err := io.Copy(outputRouter, sess.PtyReader()); err != nil {
// The output reader normally ends on its own when the PTY master reports
// EOF after the child exits. copyCtx lets us stop it otherwise: on parent
// cancellation (Ctrl+C) and on the drain-grace path below, which guards
// against a lingering descendant keeping the slave open (no EOF).
copyCtx, stopCopy := context.WithCancel(ctx)
defer stopCopy()
copyDone := make(chan struct{})
go func() {
defer close(copyDone)
if err := sess.CopyOutputContext(copyCtx, outputRouter); err != nil {
log.Errorf("failed to copy output: %v", err)
}
})
}()
inputRouter, err := pty.NewInputRouter(sess.PtyWriter())
if err != nil {
@@ -217,7 +229,16 @@ func runPTY(
}
sessionError := sess.Wait()
wg.Wait()
// Child has exited. Let the reader drain to EOF, but bound the wait so a
// lingering descendant holding the slave open cannot block teardown.
select {
case <-copyDone:
case <-time.After(outputDrainGrace):
log.Debugf("output drain grace exceeded, stopping pty reader")
stopCopy()
<-copyDone
}
if sessionError != nil {
return wrapCommandExecutionError(sessionError, result)