Windows terminal support using the termtest library.
Should even support resizing. Fully untested.
This commit is contained in:
parent
d2801d0019
commit
55c93ad4e2
2
go.mod
2
go.mod
@ -3,6 +3,7 @@ module converge
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/ActiveState/termtest/conpty v0.5.0
|
||||
github.com/creack/pty v1.1.21
|
||||
github.com/gliderlabs/ssh v0.3.7
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
@ -13,6 +14,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
|
5
go.sum
5
go.sum
@ -1,3 +1,7 @@
|
||||
github.com/ActiveState/termtest/conpty v0.5.0 h1:JLUe6YDs4Jw4xNPCU+8VwTpniYOGeKzQg4SM2YHQNA8=
|
||||
github.com/ActiveState/termtest/conpty v0.5.0/go.mod h1:LO4208FLsxw6DcNZ1UtuGUMW+ga9PFtX4ntv8Ymg9og=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
@ -36,6 +40,7 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -10,3 +10,15 @@ type ReadWriteAddrCloser interface {
|
||||
|
||||
RemoteAddr() net.Addr
|
||||
}
|
||||
|
||||
type ReadWriterCombiner struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (rw *ReadWriterCombiner) Read(p []byte) (n int, err error) {
|
||||
return rw.Reader.Read(p)
|
||||
}
|
||||
func (rw *ReadWriterCombiner) Write(p []byte) (n int, err error) {
|
||||
return rw.Writer.Write(p)
|
||||
}
|
||||
|
@ -1,24 +1,81 @@
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ActiveState/termtest/conpty"
|
||||
"github.com/gliderlabs/ssh"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var PtySpawner = Spawner(func(sshSession ssh.Session, env []string, name string, arg ...string) (Process, error) {
|
||||
return nil, nil
|
||||
var PtySpawner = Spawner(func(sshSession ssh.Session, env []string, name string, args ...string) (Process, error) {
|
||||
_, winCh, isPty := sshSession.Pty()
|
||||
if !isPty {
|
||||
return nil, fmt.Errorf("ssh session is not a pty")
|
||||
}
|
||||
|
||||
cpty, err := conpty.New(80, 25)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pid, _, err := cpty.Spawn(
|
||||
"cmd.exe",
|
||||
args,
|
||||
&syscall.ProcAttr{
|
||||
Env: env,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
cpty.Close()
|
||||
return nil, err
|
||||
}
|
||||
fmt.Printf("New process with pid %d spawned\n", pid)
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
cpty.Close()
|
||||
return nil, fmt.Errorf("Failed to find process: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for win := range winCh {
|
||||
err = cpty.Resize(uint16(win.Width), uint16(win.Height))
|
||||
if err != nil {
|
||||
log.Printf("Feiled to resize terminal to %d x %d", win.Width, win.Height)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ptyProcess{
|
||||
cpty: cpty,
|
||||
process: process,
|
||||
}, nil
|
||||
})
|
||||
|
||||
type ptyProcess struct {
|
||||
cmd *exec.Cmd
|
||||
f *os.File
|
||||
cpty *conpty.ConPty
|
||||
process *os.Process
|
||||
}
|
||||
|
||||
func (proc ptyProcess) Read(p []byte) (n int, err error) {
|
||||
return proc.cpty.OutPipe().Read(p)
|
||||
}
|
||||
func (proc ptyProcess) Write(p []byte) (n int, err error) {
|
||||
return proc.Write(p)
|
||||
}
|
||||
|
||||
func (p ptyProcess) Pipe() io.ReadWriter {
|
||||
return p.f
|
||||
return p
|
||||
}
|
||||
|
||||
func (p ptyProcess) Wait() error {
|
||||
return p.cmd.Wait()
|
||||
defer p.cpty.Close()
|
||||
ps, err := p.process.Wait()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting for process: %v", err)
|
||||
}
|
||||
if ps.ExitCode() != 0 {
|
||||
return fmt.Errorf("exit code was: %d\n", ps.ExitCode())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user