3
3
package pty
4
4
5
5
import (
6
+ "context"
6
7
"fmt"
7
- "os/exec"
8
8
"runtime"
9
9
"strings"
10
10
"syscall"
11
11
12
12
"golang.org/x/xerrors"
13
13
)
14
14
15
- func startPty (cmd * exec. Cmd , opt ... StartOption ) (retPTY * otherPty , proc Process , err error ) {
15
+ func startPty (cmdPty * Cmd , opt ... StartOption ) (retPTY * otherPty , proc Process , err error ) {
16
16
var opts startOptions
17
17
for _ , o := range opt {
18
18
o (& opts )
@@ -23,30 +23,34 @@ func startPty(cmd *exec.Cmd, opt ...StartOption) (retPTY *otherPty, proc Process
23
23
return nil , nil , xerrors .Errorf ("newPty failed: %w" , err )
24
24
}
25
25
26
- origEnv := cmd .Env
26
+ origEnv := cmdPty .Env
27
27
if opty .opts .sshReq != nil {
28
- cmd .Env = append (cmd .Env , fmt .Sprintf ("SSH_TTY=%s" , opty .Name ()))
28
+ cmdPty .Env = append (cmdPty .Env , fmt .Sprintf ("SSH_TTY=%s" , opty .Name ()))
29
29
}
30
30
if opty .opts .setGPGTTY {
31
- cmd .Env = append (cmd .Env , fmt .Sprintf ("GPG_TTY=%s" , opty .Name ()))
31
+ cmdPty .Env = append (cmdPty .Env , fmt .Sprintf ("GPG_TTY=%s" , opty .Name ()))
32
32
}
33
+ if cmdPty .Context == nil {
34
+ cmdPty .Context = context .Background ()
35
+ }
36
+ cmdExec := cmdPty .AsExec ()
33
37
34
- cmd .SysProcAttr = & syscall.SysProcAttr {
38
+ cmdExec .SysProcAttr = & syscall.SysProcAttr {
35
39
Setsid : true ,
36
40
Setctty : true ,
37
41
}
38
- cmd .Stdout = opty .tty
39
- cmd .Stderr = opty .tty
40
- cmd .Stdin = opty .tty
41
- err = cmd .Start ()
42
+ cmdExec .Stdout = opty .tty
43
+ cmdExec .Stderr = opty .tty
44
+ cmdExec .Stdin = opty .tty
45
+ err = cmdExec .Start ()
42
46
if err != nil {
43
47
_ = opty .Close ()
44
48
if runtime .GOOS == "darwin" && strings .Contains (err .Error (), "bad file descriptor" ) {
45
49
// macOS has an obscure issue where the PTY occasionally closes
46
50
// before it's used. It's unknown why this is, but creating a new
47
51
// TTY resolves it.
48
- cmd .Env = origEnv
49
- return startPty (cmd , opt ... )
52
+ cmdPty .Env = origEnv
53
+ return startPty (cmdPty , opt ... )
50
54
}
51
55
return nil , nil , xerrors .Errorf ("start: %w" , err )
52
56
}
@@ -64,14 +68,14 @@ func startPty(cmd *exec.Cmd, opt ...StartOption) (retPTY *otherPty, proc Process
64
68
// confirming this, but I did find a thread of someone else's
65
69
// observations: https://developer.apple.com/forums/thread/663632
66
70
if err := opty .tty .Close (); err != nil {
67
- _ = cmd .Process .Kill ()
71
+ _ = cmdExec .Process .Kill ()
68
72
return nil , nil , xerrors .Errorf ("close tty: %w" , err )
69
73
}
70
74
opty .tty = nil // remove so we don't attempt to close it again.
71
75
}
72
76
oProcess := & otherProcess {
73
77
pty : opty .pty ,
74
- cmd : cmd ,
78
+ cmd : cmdExec ,
75
79
cmdDone : make (chan any ),
76
80
}
77
81
go oProcess .waitInternal ()
0 commit comments