mirror of https://github.com/liamg/aminal.git
Implemented basic platform abstraction layer for Pty and Process creation;
Added a platform package that exposes a few interfaces and provides different implementations for different platforms; Windows build and dev env setup instructions; Setup Travis Linux to run tests and build sources.
This commit is contained in:
parent
bf90bfb334
commit
92a0bf245c
|
@ -0,0 +1,25 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- "1.10.5"
|
||||
- "1.11.2"
|
||||
- "master" # find out if an upcoming change in Go is going to break us
|
||||
|
||||
matrix:
|
||||
# We only want to fail the build based on stable versions of Go
|
||||
allow_failures:
|
||||
- go: master
|
||||
fast_finish: true
|
||||
|
||||
go_import_path: github.com/liamg/aminal
|
||||
|
||||
before_install:
|
||||
- sudo apt-get install -y xorg-dev libgl1-mesa-dev
|
||||
|
||||
script:
|
||||
- make test
|
||||
- make build-linux
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: MpOY0NYnuf8hgDVP4MjSSrrzWDdPlJ5JnB/TiiJxptjN2qn0OKPVBeZl2OsJ3MlZfjNM3wZ3mNN6p/3TwJmfp1g+3SU9MfRul4XMFfJKiN9u5/y5lamophs+vkgrawG00xwMd4KvKOqXVP2vX2s+koVfUzUXEot5IJDMerQltQPqbonvk/tWJHmtu5NoMQgGO+2pvmy+74u5HMfjoWSmTBiJgTUZ8c/a1nK3MsG2mafsEB8sLa8uMWAp9ISnfxLzTTUFQeVR64i1z7duz5fJ0B96JqYIlwnR9vzeB1gr+3+cSdDUPfcTgWEDhDn9Kglqe71K+9vUaP3cOkEMThFPoj1wb2vyIV2LYVqsAVAmxBFiyMS8HVkp7z0M7f34wRhd3blN2KaxYuiFlSg3MwnUp615NHnnS8kA0So/E7xYcXnsfFx9f1ZZqaAuHz1DrD2UHeRKtcekdcxTMG4LMJbGv+HsqL6mUFIND/tN9h/QV+w+GbmKUUBt/xMmyoaLqBwKz+m1aLvBSZ9IaUIHRKCNnCfm9QPXoMfeXvh2JCX7leM/0FDHUp8v1J1Rw5E0eiWpBS0OlQS2OeR8zAlJh8mZ4SpApUEHDEHBbcVSP0ZM+fSMpq1OVESlmEO308WZY0IlmQ9UkDIpixLuizDB4IlwOPVXlRSyHd9spAmqx4ZGfR4=
|
15
main.go
15
main.go
|
@ -3,12 +3,10 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/kr/pty"
|
||||
"github.com/liamg/aminal/gui"
|
||||
"github.com/liamg/aminal/platform"
|
||||
"github.com/liamg/aminal/terminal"
|
||||
"github.com/riywo/loginshell"
|
||||
)
|
||||
|
@ -26,7 +24,8 @@ func main() {
|
|||
defer logger.Sync()
|
||||
|
||||
logger.Infof("Allocating pty...")
|
||||
pty, tty, err := pty.Open()
|
||||
|
||||
pty, err := platform.NewPty(80, 25)
|
||||
if err != nil {
|
||||
logger.Fatalf("Failed to allocate pty: %s", err)
|
||||
}
|
||||
|
@ -43,12 +42,8 @@ func main() {
|
|||
os.Setenv("TERM", "xterm-256color") // controversial! easier than installing terminfo everywhere, but obviously going to be slightly different to xterm functionality, so we'll see...
|
||||
os.Setenv("COLORTERM", "truecolor")
|
||||
|
||||
shell := exec.Command(shellStr)
|
||||
shell.Stdout = tty
|
||||
shell.Stdin = tty
|
||||
shell.Stderr = tty
|
||||
shell.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
|
||||
if err := shell.Start(); err != nil {
|
||||
_, err = pty.CreateGuestProcess(shellStr)
|
||||
if err != nil {
|
||||
pty.Close()
|
||||
logger.Fatalf("Failed to start your shell: %s", err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package platform
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type cmdProc struct {
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
func newCmdProc(c *exec.Cmd) *cmdProc {
|
||||
return &cmdProc{
|
||||
cmd: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *cmdProc) Close() error {
|
||||
if p == nil || p.cmd == nil || p.cmd.Process == nil {
|
||||
return nil
|
||||
}
|
||||
ret := p.cmd.Process.Kill()
|
||||
p.cmd = nil
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package platform
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Process represents a child process by pid or HPROCESS in a platform-independent way
|
||||
type Process interface {
|
||||
io.Closer
|
||||
|
||||
// TODO: make useful stuff here
|
||||
}
|
||||
|
||||
// Pty represents a pseudo-terminal either by pty/tty file pair or by HCON
|
||||
type Pty interface {
|
||||
io.ReadWriteCloser
|
||||
|
||||
Resize(x int, y int) error
|
||||
CreateGuestProcess(imagePath string) (Process, error)
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
//+build !windows
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
type unixPty struct {
|
||||
pty *os.File
|
||||
tty *os.File
|
||||
}
|
||||
|
||||
type winsize struct {
|
||||
Height uint16
|
||||
Width uint16
|
||||
x uint16 //ignored, but necessary for ioctl calls
|
||||
y uint16 //ignored, but necessary for ioctl calls
|
||||
}
|
||||
|
||||
func (p *unixPty) Read(b []byte) (int, error) {
|
||||
if p == nil || p.pty == nil {
|
||||
return 0, errors.New("Attempted to read from a deallocated pty")
|
||||
}
|
||||
return p.pty.Read(b)
|
||||
}
|
||||
|
||||
func (p *unixPty) Write(b []byte) (int, error) {
|
||||
if p == nil || p.pty == nil {
|
||||
return 0, errors.New("Attempted to write to a deallocated pty")
|
||||
}
|
||||
return p.pty.Write(b)
|
||||
}
|
||||
|
||||
func (p *unixPty) Close() error {
|
||||
if p == nil || p.pty == nil {
|
||||
return nil
|
||||
}
|
||||
ret := p.pty.Close()
|
||||
p.pty = nil
|
||||
p.tty = nil
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *unixPty) Resize(x, y int) error {
|
||||
size := winsize{
|
||||
Height: uint16(y),
|
||||
Width: uint16(x),
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(p.pty.Fd()),
|
||||
uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(&size)))
|
||||
|
||||
if errno != 0 {
|
||||
return errors.New(errno.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *unixPty) CreateGuestProcess(imagePath string) (Process, error) {
|
||||
if p == nil || p.tty == nil {
|
||||
return nil, errors.New("Attempted to create a process on a deallocated pty")
|
||||
}
|
||||
shell := newCmdProc(exec.Command(imagePath))
|
||||
shell.cmd.Stdout = p.tty
|
||||
shell.cmd.Stdin = p.tty
|
||||
shell.cmd.Stderr = p.tty
|
||||
shell.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
|
||||
if err := shell.cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return shell, nil
|
||||
}
|
||||
|
||||
func NewPty(x, y int) (Pty, error) {
|
||||
innerPty, innerTty, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &unixPty{
|
||||
pty: innerPty,
|
||||
tty: innerTty,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
// +build windows,cgo
|
||||
|
||||
package platform
|
||||
|
||||
// #include "Windows.h"
|
||||
//
|
||||
// /* Until we can specify the platform SDK and target version for Windows.h *
|
||||
// * without breaking our ability to gracefully display an error message, these *
|
||||
// * definitions will be copied from the platform SDK headers and made to work. *
|
||||
// */
|
||||
//
|
||||
// typedef BOOL (* InitializeProcThreadAttributeListProcType)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD, PSIZE_T);
|
||||
// typedef BOOL (* UpdateProcThreadAttributeProcType)(
|
||||
// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
|
||||
// DWORD dwFlags,
|
||||
// DWORD_PTR Attribute,
|
||||
// PVOID lpValue,
|
||||
// SIZE_T cbSize,
|
||||
// PVOID lpPreviousValue,
|
||||
// PSIZE_T lpReturnSize
|
||||
// );
|
||||
//
|
||||
// InitializeProcThreadAttributeListProcType pfnInitializeProcThreadAttributeList = NULL;
|
||||
// UpdateProcThreadAttributeProcType pfnUpdateProcThreadAttribute = NULL;
|
||||
//
|
||||
// #define ProcThreadAttributePseudoConsole_copy 22
|
||||
//
|
||||
// #define PROC_THREAD_ATTRIBUTE_NUMBER_copy 0x0000FFFF
|
||||
// #define PROC_THREAD_ATTRIBUTE_THREAD_copy 0x00010000 // Attribute may be used with thread creation
|
||||
// #define PROC_THREAD_ATTRIBUTE_INPUT_copy 0x00020000 // Attribute is input only
|
||||
// #define PROC_THREAD_ATTRIBUTE_ADDITIVE_copy 0x00040000 // Attribute may be "accumulated," e.g. bitmasks, counters, etc.
|
||||
//
|
||||
// #define ProcThreadAttributeValue_copy(Number, Thread, Input, Additive) \
|
||||
// (((Number) & PROC_THREAD_ATTRIBUTE_NUMBER_copy) | \
|
||||
// ((Thread != FALSE) ? PROC_THREAD_ATTRIBUTE_THREAD_copy : 0) | \
|
||||
// ((Input != FALSE) ? PROC_THREAD_ATTRIBUTE_INPUT_copy : 0) | \
|
||||
// ((Additive != FALSE) ? PROC_THREAD_ATTRIBUTE_ADDITIVE_copy : 0))
|
||||
//
|
||||
// #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE_copy ProcThreadAttributeValue_copy (ProcThreadAttributePseudoConsole_copy, FALSE, TRUE, FALSE)
|
||||
//
|
||||
// typedef struct _STARTUPINFOEXW_copy {
|
||||
// STARTUPINFOW StartupInfo;
|
||||
// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
|
||||
// } STARTUPINFOEXW_copy, *LPSTARTUPINFOEXW_copy;
|
||||
//
|
||||
// HMODULE hLibKernel32_Proc = NULL;
|
||||
//
|
||||
// DWORD initProcKernFuncs()
|
||||
// {
|
||||
// hLibKernel32_Proc = LoadLibrary( "kernel32.dll" );
|
||||
// if( hLibKernel32_Proc == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// pfnInitializeProcThreadAttributeList = (InitializeProcThreadAttributeListProcType) GetProcAddress(hLibKernel32_Proc, "InitializeProcThreadAttributeList" );
|
||||
// if( pfnInitializeProcThreadAttributeList == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// pfnUpdateProcThreadAttribute = (UpdateProcThreadAttributeProcType) GetProcAddress(hLibKernel32_Proc, "UpdateProcThreadAttribute" );
|
||||
// if( pfnUpdateProcThreadAttribute == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// DWORD createGuestProcHelper( uintptr_t hpc, LPCWSTR imagePath, uintptr_t * hProcess )
|
||||
// {
|
||||
// STARTUPINFOEXW_copy si;
|
||||
// ZeroMemory( &si, sizeof(si) );
|
||||
// si.StartupInfo.cb = sizeof(si);
|
||||
//
|
||||
// size_t bytesRequired;
|
||||
// (*pfnInitializeProcThreadAttributeList)( NULL, 1, 0, &bytesRequired );
|
||||
//
|
||||
// si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
|
||||
// if( !si.lpAttributeList )
|
||||
// {
|
||||
// return E_OUTOFMEMORY;
|
||||
// }
|
||||
//
|
||||
// if (!(*pfnInitializeProcThreadAttributeList)(si.lpAttributeList, 1, 0, &bytesRequired))
|
||||
// {
|
||||
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||
// return HRESULT_FROM_WIN32(GetLastError());
|
||||
// }
|
||||
//
|
||||
// if (!(*pfnUpdateProcThreadAttribute)(si.lpAttributeList,
|
||||
// 0,
|
||||
// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE_copy,
|
||||
// (PVOID) hpc,
|
||||
// sizeof(hpc),
|
||||
// NULL,
|
||||
// NULL))
|
||||
// {
|
||||
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||
// return HRESULT_FROM_WIN32(GetLastError());
|
||||
// }
|
||||
//
|
||||
// bytesRequired = (wcslen(imagePath) + 1) * sizeof(wchar_t); // +1 null terminator
|
||||
// PWSTR cmdLineMutable = (PWSTR)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
|
||||
//
|
||||
// if (!cmdLineMutable)
|
||||
// {
|
||||
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||
// return E_OUTOFMEMORY;
|
||||
// }
|
||||
//
|
||||
// wcscpy_s(cmdLineMutable, bytesRequired, imagePath);
|
||||
//
|
||||
// PROCESS_INFORMATION pi;
|
||||
// ZeroMemory(&pi, sizeof(pi));
|
||||
//
|
||||
// if (!CreateProcessW(NULL,
|
||||
// cmdLineMutable,
|
||||
// NULL,
|
||||
// NULL,
|
||||
// FALSE,
|
||||
// EXTENDED_STARTUPINFO_PRESENT,
|
||||
// NULL,
|
||||
// NULL,
|
||||
// &si.StartupInfo,
|
||||
// &pi))
|
||||
// {
|
||||
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||
// HeapFree(GetProcessHeap(), 0, cmdLineMutable);
|
||||
// return HRESULT_FROM_WIN32(GetLastError());
|
||||
// }
|
||||
//
|
||||
// *hProcess = (uintptr_t) pi.hProcess;
|
||||
//
|
||||
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
|
||||
// HeapFree(GetProcessHeap(), 0, cmdLineMutable);
|
||||
// return S_OK;
|
||||
// }
|
||||
//
|
||||
// int hr_succeeded( DWORD hResult );
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
var procsInitSucceeded = false
|
||||
|
||||
func init() {
|
||||
ret := int(C.initProcKernFuncs())
|
||||
procsInitSucceeded = (ret == 0)
|
||||
}
|
||||
|
||||
type winProcess struct {
|
||||
hproc uintptr
|
||||
}
|
||||
|
||||
func createPtyChildProcess(imagePath string, hcon uintptr) (Process, error) {
|
||||
path16 := utf16.Encode([]rune(imagePath))
|
||||
|
||||
cpath16 := C.calloc(C.size_t(len(path16)+1), 2)
|
||||
pp := (*[1 << 30]uint16)(cpath16)
|
||||
copy(pp[:], path16)
|
||||
|
||||
hproc := C.uintptr_t(0)
|
||||
|
||||
hr := C.createGuestProcHelper(C.uintptr_t(hcon), (C.LPCWSTR)(cpath16), &hproc)
|
||||
|
||||
C.free(cpath16)
|
||||
|
||||
if int(C.hr_succeeded(hr)) == 0 {
|
||||
return nil, errors.New("Failed to create process: " + imagePath)
|
||||
}
|
||||
|
||||
return &winProcess{
|
||||
hproc: uintptr(hproc),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (process *winProcess) Close() error {
|
||||
return syscall.CloseHandle(syscall.Handle(process.hproc))
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
// +build windows,cgo
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
|
||||
"github.com/MaxRis/w32"
|
||||
)
|
||||
|
||||
// #include "Windows.h"
|
||||
//
|
||||
// /* Until we can specify the platform SDK and target version for Windows.h *
|
||||
// * without breaking our ability to gracefully display an error message, these *
|
||||
// * definitions will be copied from the platform SDK headers and made to work. *
|
||||
// */
|
||||
//
|
||||
// typedef HRESULT (* CreatePseudoConsoleProcType)( COORD, HANDLE, HANDLE, DWORD, uintptr_t * );
|
||||
// typedef HRESULT (* ResizePseudoConsoleProcType)( uintptr_t, COORD );
|
||||
// typedef HRESULT (* ClosePseudoConsoleProcType)( uintptr_t );
|
||||
//
|
||||
//
|
||||
// CreatePseudoConsoleProcType pfnCreatePseudoConsole = NULL;
|
||||
// ResizePseudoConsoleProcType pfnResizePseudoConsole = NULL;
|
||||
// ClosePseudoConsoleProcType pfnClosePseudoConsole = NULL;
|
||||
//
|
||||
// HMODULE hLibKernel32_Kern = NULL;
|
||||
//
|
||||
// DWORD initPtyKernFuncs()
|
||||
// {
|
||||
// hLibKernel32_Kern = LoadLibrary( "kernel32.dll" );
|
||||
// if( hLibKernel32_Kern == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// pfnCreatePseudoConsole = (CreatePseudoConsoleProcType) GetProcAddress(hLibKernel32_Kern, "CreatePseudoConsole" );
|
||||
// if( pfnCreatePseudoConsole == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// pfnResizePseudoConsole = (ResizePseudoConsoleProcType) GetProcAddress(hLibKernel32_Kern, "ResizePseudoConsole" );
|
||||
// if( pfnResizePseudoConsole == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// pfnClosePseudoConsole = (ClosePseudoConsoleProcType) GetProcAddress(hLibKernel32_Kern, "ClosePseudoConsole" );
|
||||
// if( pfnClosePseudoConsole == NULL )
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// DWORD createPtyHelper( int xSize, int ySize, HANDLE input, HANDLE output, DWORD flags, uintptr_t * phPC )
|
||||
// {
|
||||
// COORD size;
|
||||
// size.X = xSize;
|
||||
// size.Y = ySize;
|
||||
// return (DWORD) (*pfnCreatePseudoConsole)( size, input, output, flags, phPC );
|
||||
// }
|
||||
//
|
||||
// DWORD resizePtyHelper( uintptr_t hpc, int xSize, int ySize )
|
||||
// {
|
||||
// COORD size;
|
||||
// size.X = xSize;
|
||||
// size.Y = ySize;
|
||||
// return (DWORD) (*pfnResizePseudoConsole)( hpc, size );
|
||||
// }
|
||||
//
|
||||
// DWORD closePtyHelper( uintptr_t hpc )
|
||||
// {
|
||||
// return (DWORD) (*pfnClosePseudoConsole)( hpc );
|
||||
// }
|
||||
//
|
||||
// int hr_succeeded( DWORD hResult )
|
||||
// {
|
||||
// return SUCCEEDED( hResult );
|
||||
// }
|
||||
import "C"
|
||||
|
||||
var ptyInitSucceeded = false
|
||||
|
||||
func init() {
|
||||
ret := int(C.initPtyKernFuncs())
|
||||
ptyInitSucceeded = (ret == 0)
|
||||
}
|
||||
|
||||
type winConPty struct {
|
||||
inPipe syscall.Handle
|
||||
outPipe syscall.Handle
|
||||
innerInPipe syscall.Handle
|
||||
innerOutPipe syscall.Handle
|
||||
hcon uintptr
|
||||
}
|
||||
|
||||
func (pty *winConPty) Read(p []byte) (n int, err error) {
|
||||
return syscall.Read(pty.inPipe, p)
|
||||
}
|
||||
|
||||
func (pty *winConPty) Write(p []byte) (n int, err error) {
|
||||
return syscall.Write(pty.outPipe, p)
|
||||
}
|
||||
|
||||
func (pty *winConPty) Close() error {
|
||||
C.closePtyHelper(C.uintptr_t(pty.hcon))
|
||||
|
||||
err := syscall.CloseHandle(pty.inPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = syscall.CloseHandle(pty.outPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = syscall.CloseHandle(pty.innerInPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = syscall.CloseHandle(pty.innerOutPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pty.hcon = 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pty *winConPty) CreateGuestProcess(imagePath string) (Process, error) {
|
||||
return createPtyChildProcess(imagePath, pty.hcon)
|
||||
}
|
||||
|
||||
func (pty *winConPty) Resize(x, y int) error {
|
||||
cret := C.resizePtyHelper(C.uintptr_t(pty.hcon), C.int(x), C.int(y))
|
||||
|
||||
if int(C.hr_succeeded(cret)) == 0 {
|
||||
return errors.New("Failed to resize ConPTY")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPty creates a new instance of a Pty implementation for Windows on a newly allocated ConPTY
|
||||
func NewPty(x, y int) (pty Pty, err error) {
|
||||
if !ptyInitSucceeded {
|
||||
w32.MessageBox(0, "Aminal requires APIs that are only available on Windows 10 1809 (October 2018 Update) or above. Please upgrade", "Aminal", 0)
|
||||
return nil, errors.New("Windows PseudoConsole API unavailable on this version of Windows")
|
||||
}
|
||||
pty = nil
|
||||
|
||||
var inputReadSide, inputWriteSide syscall.Handle
|
||||
var outputReadSide, outputWriteSide syscall.Handle
|
||||
|
||||
err = syscall.CreatePipe(&inputReadSide, &inputWriteSide, nil, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = syscall.CreatePipe(&outputReadSide, &outputWriteSide, nil, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var hc C.uintptr_t
|
||||
|
||||
cret := C.createPtyHelper(C.int(x), C.int(y), C.HANDLE(inputReadSide), C.HANDLE(outputWriteSide), 0, &hc)
|
||||
ret := int(cret)
|
||||
|
||||
if ret != 0 {
|
||||
return nil, errors.New("Failed to allocate a ConPTY instance")
|
||||
}
|
||||
|
||||
pty = &winConPty{
|
||||
inPipe: outputReadSide,
|
||||
outPipe: inputWriteSide,
|
||||
innerInPipe: inputReadSide,
|
||||
innerOutPipe: outputWriteSide,
|
||||
hcon: uintptr(hc),
|
||||
}
|
||||
|
||||
return pty, nil
|
||||
}
|
|
@ -4,13 +4,11 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/liamg/aminal/buffer"
|
||||
"github.com/liamg/aminal/config"
|
||||
"github.com/liamg/aminal/platform"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -36,7 +34,7 @@ type Terminal struct {
|
|||
buffers []*buffer.Buffer
|
||||
activeBuffer *buffer.Buffer
|
||||
lock sync.Mutex
|
||||
pty *os.File
|
||||
pty platform.Pty
|
||||
logger *zap.SugaredLogger
|
||||
title string
|
||||
size Winsize
|
||||
|
@ -64,7 +62,7 @@ type Winsize struct {
|
|||
y uint16 //ignored, but necessary for ioctl calls
|
||||
}
|
||||
|
||||
func New(pty *os.File, logger *zap.SugaredLogger, config *config.Config) *Terminal {
|
||||
func New(pty platform.Pty, logger *zap.SugaredLogger, config *config.Config) *Terminal {
|
||||
t := &Terminal{
|
||||
buffers: []*buffer.Buffer{
|
||||
buffer.NewBuffer(1, 1, buffer.CellAttributes{
|
||||
|
@ -280,9 +278,8 @@ func (terminal *Terminal) SetSize(newCols uint, newLines uint) error {
|
|||
terminal.size.Width = uint16(newCols)
|
||||
terminal.size.Height = uint16(newLines)
|
||||
|
||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(terminal.pty.Fd()),
|
||||
uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(&terminal.size)))
|
||||
if err != 0 {
|
||||
err := terminal.pty.Resize(int(newCols), int(newLines))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to set terminal size vai ioctl: Error no %d", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
### Windows dev env setup and build instructions:
|
||||
|
||||
1. Setup choco package manager https://chocolatey.org/docs/installation
|
||||
2. Use `choco` to install golang and mingw
|
||||
```choco install golang mingw```
|
||||
|
||||
|
||||
### Setting aminal GoLang build env and directories structures for the project:
|
||||
|
||||
```
|
||||
cd %YOUR_PROJECT_WORKING_DIR%
|
||||
mkdir go\src\github.com\liamg
|
||||
cd go\src\github.com\liamg
|
||||
git clone git@github.com:jumptrading/aminal-mirror.git
|
||||
move aminal-mirror aminal
|
||||
|
||||
set GOPATH=%YOUR_PROJECT_WORKING_DIR%\go
|
||||
set GOBIN=%GOPATH%/bin
|
||||
set PATH=%GOBIN%;%PATH%
|
||||
|
||||
cd aminal
|
||||
go get
|
||||
go build
|
||||
go install
|
||||
```
|
||||
|
||||
Look for the aminal.exe built binary under your %GOBIN% path
|
||||
|
Loading…
Reference in New Issue