Skip to content

Commit 79d349f

Browse files
committed
Add support for running sub-processes under a PTY
This is really nice for running programs that output colour, such as coloured log lines, etc. I defaulted it to off because some applications when run under a PTY will attempt to move the cursor around, clear lines, and so on, so it should be up to the user to decide whether to enable it.
1 parent ebb9736 commit 79d349f

File tree

6 files changed

+46
-3
lines changed

6 files changed

+46
-3
lines changed

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ require (
99
gopkg.in/yaml.v3 v3.0.1
1010
)
1111

12-
require github.com/mattn/go-isatty v0.0.17 // indirect
12+
require (
13+
github.com/creack/pty v1.1.18
14+
github.com/mattn/go-isatty v0.0.17 // indirect
15+
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
2+
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
13
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
24
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
35
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=

main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ var exitOnStop = flag.Bool("exit-on-stop", true, "Exit goreman if all subprocess
9898
// show timestamp in log
9999
var logTime = flag.Bool("logtime", true, "show timestamp in log")
100100

101+
// use a PTY for all subprocesses
102+
var usePty = flag.Bool("pty", false, "use a PTY for all subprocesses (noop on Windows)")
103+
101104
var maxProcNameLength = 0
102105

103106
var re = regexp.MustCompile(`\$([a-zA-Z]+[a-zA-Z0-9_]+)`)

proc.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ func spawnProc(name string, errCh chan<- error) {
1717
cs := append(cmdStart, proc.cmdline)
1818
cmd := exec.Command(cs[0], cs[1:]...)
1919
cmd.Stdin = nil
20-
cmd.Stdout = logger
21-
cmd.Stderr = logger
2220
cmd.SysProcAttr = procAttrs
2321

22+
if err := startPTY(logger, cmd); err != nil {
23+
select {
24+
case errCh <- err:
25+
default:
26+
}
27+
fmt.Fprintf(logger, "Failed to open pty for %s: %s\n", name, err)
28+
return
29+
}
2430
if proc.setPort {
2531
cmd.Env = append(os.Environ(), fmt.Sprintf("PORT=%d", proc.port))
2632
fmt.Fprintf(logger, "Starting %s on port %d\n", name, proc.port)

proc_posix.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
package main
55

66
import (
7+
"fmt"
8+
"io"
79
"os"
10+
"os/exec"
811
"os/signal"
912

13+
"github.com/creack/pty"
1014
"golang.org/x/sys/unix"
1115
)
1216

@@ -51,3 +55,21 @@ func notifyCh() <-chan os.Signal {
5155
signal.Notify(sc, sigterm, sigint, sighup)
5256
return sc
5357
}
58+
59+
func startPTY(logger *clogger, cmd *exec.Cmd) error {
60+
if *usePty {
61+
p, t, err := pty.Open()
62+
if err != nil {
63+
return fmt.Errorf("failed to open PTY: %w", err)
64+
}
65+
defer p.Close()
66+
defer t.Close()
67+
cmd.Stdout = t
68+
cmd.Stderr = t
69+
go io.Copy(logger, p)
70+
} else {
71+
cmd.Stdout = logger
72+
cmd.Stderr = logger
73+
}
74+
return nil
75+
}

proc_windows.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"os"
5+
"os/exec"
56
"os/signal"
67
"syscall"
78

@@ -63,3 +64,9 @@ func notifyCh() <-chan os.Signal {
6364
signal.Notify(sc, os.Interrupt)
6465
return sc
6566
}
67+
68+
// This is a no-op on Windows.
69+
func startPTY(logger *clogger, cmd *exec.Cmd) error {
70+
cmd.Stdout = logger
71+
cmd.Stderr = logger
72+
}

0 commit comments

Comments
 (0)