From 7a4e5dae2454383b7c406a6367383d83eb5592a2 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 16:53:18 +0530 Subject: [PATCH 01/13] Add dmsg close to initDmsg --- pkg/visor/init.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pkg/visor/init.go b/pkg/visor/init.go index 5607150d0d..4255d5504b 100644 --- a/pkg/visor/init.go +++ b/pkg/visor/init.go @@ -212,9 +212,22 @@ func initDmsg(ctx context.Context, v *Visor, log *logging.Logger) error { } dmsgC := dmsgc.New(v.conf.PK, v.conf.SK, v.ebc, v.conf.Dmsg) - time.Sleep(200 * time.Millisecond) - go dmsgC.Serve(context.Background()) - time.Sleep(200 * time.Millisecond) + wg := new(sync.WaitGroup) + wg.Add(1) + go func() { + defer wg.Done() + time.Sleep(200 * time.Millisecond) + go dmsgC.Serve(context.Background()) + time.Sleep(200 * time.Millisecond) + }() + + v.pushCloseStack("dmsg", func() error { + if err := dmsgC.Close(); err != nil { + return err + } + wg.Wait() + return nil + }) v.initLock.Lock() v.dmsgC = dmsgC From 4508a1179ca901d4b60f9d758ddf21c704285482 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 17:35:04 +0530 Subject: [PATCH 02/13] Test dep --- go.mod | 2 +- go.sum | 9 +- .../ActiveState/termtest/conpty/LICENSE | 29 + .../ActiveState/termtest/conpty/README.md | 23 + .../termtest/conpty/conpty_windows.go | 250 ++++++ .../ActiveState/termtest/conpty/doc.go | 11 + .../termtest/conpty/exec_windows.go | 161 ++++ .../ActiveState/termtest/conpty/go.mod | 8 + .../ActiveState/termtest/conpty/go.sum | 4 + .../termtest/conpty/syscall_windows.go | 112 +++ .../ActiveState/termtest/conpty/term_other.go | 7 + .../termtest/conpty/term_windows.go | 61 ++ vendor/github.com/Azure/go-ansiterm/LICENSE | 21 + vendor/github.com/Azure/go-ansiterm/README.md | 12 + .../github.com/Azure/go-ansiterm/constants.go | 188 +++++ .../github.com/Azure/go-ansiterm/context.go | 7 + .../Azure/go-ansiterm/csi_entry_state.go | 49 ++ .../Azure/go-ansiterm/csi_param_state.go | 38 + .../go-ansiterm/escape_intermediate_state.go | 36 + .../Azure/go-ansiterm/escape_state.go | 47 ++ .../Azure/go-ansiterm/event_handler.go | 90 +++ .../Azure/go-ansiterm/ground_state.go | 24 + .../Azure/go-ansiterm/osc_string_state.go | 31 + vendor/github.com/Azure/go-ansiterm/parser.go | 151 ++++ .../go-ansiterm/parser_action_helpers.go | 99 +++ .../Azure/go-ansiterm/parser_actions.go | 119 +++ vendor/github.com/Azure/go-ansiterm/states.go | 71 ++ .../github.com/Azure/go-ansiterm/utilities.go | 21 + .../Azure/go-ansiterm/winterm/ansi.go | 182 +++++ .../Azure/go-ansiterm/winterm/api.go | 327 ++++++++ .../go-ansiterm/winterm/attr_translation.go | 100 +++ .../go-ansiterm/winterm/cursor_helpers.go | 101 +++ .../go-ansiterm/winterm/erase_helpers.go | 84 ++ .../go-ansiterm/winterm/scroll_helper.go | 118 +++ .../Azure/go-ansiterm/winterm/utilities.go | 9 + .../go-ansiterm/winterm/win_event_handler.go | 743 ++++++++++++++++++ vendor/github.com/skycoin/dmsg/.gitignore | 1 + vendor/github.com/skycoin/dmsg/Makefile | 33 +- vendor/github.com/skycoin/dmsg/client.go | 14 +- .../skycoin/dmsg/cmdutil/service_flags.go | 2 - .../skycoin/dmsg/cmdutil/signal_context.go | 2 +- vendor/github.com/skycoin/dmsg/disc/client.go | 57 +- .../skycoin/dmsg/disc/http_message.go | 1 + .../github.com/skycoin/dmsg/disc/testing.go | 12 + vendor/github.com/skycoin/dmsg/dmsgpty/cli.go | 53 +- .../skycoin/dmsg/dmsgpty/cli_unix.go | 63 ++ .../skycoin/dmsg/dmsgpty/cli_windows.go | 44 ++ .../github.com/skycoin/dmsg/dmsgpty/conf.go | 52 +- .../github.com/skycoin/dmsg/dmsgpty/const.go | 12 - .../skycoin/dmsg/dmsgpty/const_unix.go | 24 + .../skycoin/dmsg/dmsgpty/const_windows.go | 27 + .../github.com/skycoin/dmsg/dmsgpty/host.go | 10 +- .../skycoin/dmsg/dmsgpty/pty_client.go | 41 +- .../dmsg/dmsgpty/pty_client_windows.go | 31 + .../skycoin/dmsg/dmsgpty/pty_gateway.go | 48 +- .../skycoin/dmsg/dmsgpty/pty_gateway_unix.go | 32 + .../dmsg/dmsgpty/pty_gateway_windows.go | 28 + .../dmsg/dmsgpty/{pty.go => pty_unix.go} | 58 +- .../skycoin/dmsg/dmsgpty/pty_windows.go | 125 +++ vendor/github.com/skycoin/dmsg/dmsgpty/ui.go | 5 +- .../skycoin/dmsg/dmsgpty/ui_unix.go | 15 + .../skycoin/dmsg/dmsgpty/ui_windows.go | 16 + .../github.com/skycoin/dmsg/entity_common.go | 44 +- vendor/github.com/skycoin/dmsg/go.mod | 5 +- vendor/github.com/skycoin/dmsg/go.sum | 11 + vendor/github.com/skycoin/dmsg/server.go | 4 +- vendor/modules.txt | 8 +- 67 files changed, 4029 insertions(+), 194 deletions(-) create mode 100644 vendor/github.com/ActiveState/termtest/conpty/LICENSE create mode 100644 vendor/github.com/ActiveState/termtest/conpty/README.md create mode 100644 vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/doc.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/exec_windows.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/go.mod create mode 100644 vendor/github.com/ActiveState/termtest/conpty/go.sum create mode 100644 vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/term_other.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/term_windows.go create mode 100644 vendor/github.com/Azure/go-ansiterm/LICENSE create mode 100644 vendor/github.com/Azure/go-ansiterm/README.md create mode 100644 vendor/github.com/Azure/go-ansiterm/constants.go create mode 100644 vendor/github.com/Azure/go-ansiterm/context.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_entry_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_param_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/event_handler.go create mode 100644 vendor/github.com/Azure/go-ansiterm/ground_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/osc_string_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_actions.go create mode 100644 vendor/github.com/Azure/go-ansiterm/states.go create mode 100644 vendor/github.com/Azure/go-ansiterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/ansi.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/api.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go rename vendor/github.com/skycoin/dmsg/dmsgpty/{pty.go => pty_unix.go} (80%) create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go diff --git a/go.mod b/go.mod index f2953ba5bb..e27c75dff3 100644 --- a/go.mod +++ b/go.mod @@ -48,4 +48,4 @@ require ( ) // Uncomment for tests with alternate branches of 'dmsg' -//replace github.com/skycoin/dmsg => ../dmsg +replace github.com/skycoin/dmsg => ../dmsg diff --git a/go.sum b/go.sum index ab807602ba..c405f682fe 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,12 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +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/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51 h1:77WF6PJZQiA3OMt8Nl+PH/dbkszumosxunW36ZQj2QQ= github.com/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51/go.mod h1:EEEtt5r8y0gGHlRFF2+cLx0WUy/rKHnjALmom5E0+74= +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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= @@ -279,8 +283,6 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 h1:Dlf/sDocfSgjP+ipVxzOtDVkkLN1u6ZqUyXzp22AkU4= -github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2/go.mod h1:XguFKwECpSMq+/AKv8TCTsRlCEHSEIbqoaxOyceK2Ys= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6 h1:1Nc5EBY6pjfw1kwW0duwyG+7WliWz5u9kgk1h5MnLuA= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:UXghlricA7J3aRD/k7p/zBObQfmBawwCxIVPVjz2Q3o= github.com/skycoin/skycoin v0.26.0/go.mod h1:78nHjQzd8KG0jJJVL/j0xMmrihXi70ti63fh8vXScJw= @@ -434,17 +436,18 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/ActiveState/termtest/conpty/LICENSE b/vendor/github.com/ActiveState/termtest/conpty/LICENSE new file mode 100644 index 0000000000..0ea09c8e0d --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, ActiveState Software +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/ActiveState/termtest/conpty/README.md b/vendor/github.com/ActiveState/termtest/conpty/README.md new file mode 100644 index 0000000000..fb093f8559 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/README.md @@ -0,0 +1,23 @@ +# termtest/conpty + +Support for the [Windows pseudo +console](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/) +in Go. + +Developed as part of the cross-platform terminal automation library +[expect](https://github.com/ActiveState/termtest/expect) for the [ActiveState +state tool](https://www.activestate.com/products/platform/state-tool/). + +## Example + +See ./cmd/example/main.go + +## Client configuration + +On Windows, you may have to adjust the programme that you are running in the +pseudo-console, by configuring the standard output handler to process virtual +terminal codes. See https://docs.microsoft.com/en-us/windows/console/setconsolemode + +This package comes with a convenience function `InitTerminal()` that you can +use in your client to set this option. + diff --git a/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go b/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go new file mode 100644 index 0000000000..e0a1821fc9 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go @@ -0,0 +1,250 @@ +// Copyright 2020 ActiveState Software. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package conpty + +import ( + "fmt" + "log" + "os" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +// ConPty represents a windows pseudo console. +// Attach a process to it by calling the Spawn() method. +// You can send UTF encoded commands to it with Write() and listen to +// its output stream by accessing the output pipe via OutPipe() +type ConPty struct { + hpCon *windows.Handle + pipeFdIn windows.Handle + pipeFdOut windows.Handle + startupInfo startupInfoEx + consoleSize uintptr + inPipe *os.File + outPipe *os.File + attributeListBuffer []byte +} + +// New returns a new ConPty pseudo terminal device +func New(columns int16, rows int16) (c *ConPty, err error) { + c = &ConPty{ + hpCon: new(windows.Handle), + startupInfo: startupInfoEx{}, + consoleSize: uintptr(columns) + (uintptr(rows) << 16), + } + err = c.createPseudoConsoleAndPipes() + if err != nil { + return nil, err + } + err = c.initializeStartupInfoAttachedToPTY() + if err != nil { + return nil, err + } + return +} + +// Close closes the pseudo-terminal and cleans up all attached resources +func (c *ConPty) Close() (err error) { + err = deleteProcThreadAttributeList(c.startupInfo.lpAttributeList) + if err != nil { + log.Printf("Failed to free delete proc thread attribute list: %v", err) + } + /* + _, err = windows.LocalFree(c.startupInfo.lpAttributeList) + if err != nil { + log.Printf("Failed to free the lpAttributeList") + } + */ + err = closePseudoConsole(*c.hpCon) + if err != nil { + log.Printf("Failed to close pseudo console: %v", err) + } + c.inPipe.Close() + c.outPipe.Close() + return +} + +// OutPipe returns the output pipe of the pseudo terminal +func (c *ConPty) OutPipe() *os.File { + return c.outPipe +} + +// InPipe returns input pipe of the pseudo terminal +// Note: It is safer to use the Write method to prevent partially-written VT sequences +// from corrupting the terminal +func (c *ConPty) InPipe() *os.File { + return c.inPipe +} + +func (c *ConPty) OutFd() uintptr { + return c.outPipe.Fd() +} + +// Write safely writes bytes to the pseudo terminal +func (c *ConPty) Write(buf []byte) (uint32, error) { + var n uint32 + err := windows.WriteFile(c.pipeFdIn, buf, &n, nil) + return n, err +} + +var zeroProcAttr syscall.ProcAttr + +// Spawn spawns a new process attached to the pseudo terminal +func (c *ConPty) Spawn(argv0 string, argv []string, attr *syscall.ProcAttr) (pid int, handle uintptr, err error) { + + if attr == nil { + attr = &zeroProcAttr + } + + if attr.Sys != nil { + log.Printf("Warning: SysProc attributes are not supported by Spawn.") + } + + if len(attr.Files) != 0 { + log.Printf("Warning: Ignoring 'Files' attribute in ProcAttr argument.") + } + + if len(attr.Dir) != 0 { + // StartProcess assumes that argv0 is relative to attr.Dir, + // because it implies Chdir(attr.Dir) before executing argv0. + // Windows CreateProcess assumes the opposite: it looks for + // argv0 relative to the current directory, and, only once the new + // process is started, it does Chdir(attr.Dir). We are adjusting + // for that difference here by making argv0 absolute. + var err error + argv0, err = joinExeDirAndFName(attr.Dir, argv0) + if err != nil { + return 0, 0, err + } + } + argv0p, err := windows.UTF16PtrFromString(argv0) + if err != nil { + return 0, 0, err + } + + // Windows CreateProcess takes the command line as a single string: + // use attr.CmdLine if set, else build the command line by escaping + // and joining each argument with spaces + cmdline := makeCmdLine(argv) + + var argvp *uint16 + if len(cmdline) != 0 { + argvp, err = windows.UTF16PtrFromString(cmdline) + if err != nil { + return 0, 0, err + } + } + + var dirp *uint16 + if len(attr.Dir) != 0 { + dirp, err = windows.UTF16PtrFromString(attr.Dir) + if err != nil { + return 0, 0, err + } + } + + c.startupInfo.startupInfo.Flags = windows.STARTF_USESTDHANDLES + + pi := new(windows.ProcessInformation) + + flags := uint32(windows.CREATE_UNICODE_ENVIRONMENT) | extendedStartupinfoPresent + + var zeroSec windows.SecurityAttributes + pSec := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(zeroSec)), InheritHandle: 1} + tSec := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(zeroSec)), InheritHandle: 1} + + // c.startupInfo.startupInfo.Cb = uint32(unsafe.Sizeof(c.startupInfo)) + err = windows.CreateProcess( + argv0p, + argvp, + pSec, // process handle not inheritable + tSec, // thread handles not inheritable, + false, + flags, + createEnvBlock(addCriticalEnv(dedupEnvCase(true, attr.Env))), + dirp, // use current directory later: dirp, + &c.startupInfo.startupInfo, + pi) + + if err != nil { + return 0, 0, err + } + defer windows.CloseHandle(windows.Handle(pi.Thread)) + + return int(pi.ProcessId), uintptr(pi.Process), nil +} + +func (c *ConPty) createPseudoConsoleAndPipes() (err error) { + var hPipePTYIn windows.Handle + var hPipePTYOut windows.Handle + + if err := windows.CreatePipe(&hPipePTYIn, &c.pipeFdIn, nil, 0); err != nil { + log.Fatalf("Failed to create PTY input pipe: %v", err) + } + if err := windows.CreatePipe(&c.pipeFdOut, &hPipePTYOut, nil, 0); err != nil { + log.Fatalf("Failed to create PTY output pipe: %v", err) + } + + err = createPseudoConsole(c.consoleSize, hPipePTYIn, hPipePTYOut, c.hpCon) + if err != nil { + return fmt.Errorf("failed to create pseudo console: %d, %v", uintptr(*c.hpCon), err) + } + + // Note: We can close the handles to the PTY-end of the pipes here + // because the handles are dup'ed into the ConHost and will be released + // when the ConPTY is destroyed. + if hPipePTYOut != windows.InvalidHandle { + windows.CloseHandle(hPipePTYOut) + } + if hPipePTYIn != windows.InvalidHandle { + windows.CloseHandle(hPipePTYIn) + } + + c.inPipe = os.NewFile(uintptr(c.pipeFdIn), "|0") + c.outPipe = os.NewFile(uintptr(c.pipeFdOut), "|1") + + return +} + +func (c *ConPty) Resize(cols uint16, rows uint16) error { + return resizePseudoConsole(*c.hpCon, uintptr(cols)+(uintptr(rows)<<16)) +} + +func (c *ConPty) initializeStartupInfoAttachedToPTY() (err error) { + + var attrListSize uint64 + c.startupInfo.startupInfo.Cb = uint32(unsafe.Sizeof(c.startupInfo)) + + err = initializeProcThreadAttributeList(0, 1, &attrListSize) + if err != nil { + return fmt.Errorf("could not retrieve list size: %v", err) + } + + c.attributeListBuffer = make([]byte, attrListSize) + // c.startupInfo.lpAttributeList, err = localAlloc(attrListSize) + // if err != nil { + // return fmt.Errorf("Could not allocate local memory: %v", err) + // } + + c.startupInfo.lpAttributeList = windows.Handle(unsafe.Pointer(&c.attributeListBuffer[0])) + + err = initializeProcThreadAttributeList(uintptr(c.startupInfo.lpAttributeList), 1, &attrListSize) + if err != nil { + return fmt.Errorf("failed to initialize proc thread attributes for conpty: %v", err) + } + + err = updateProcThreadAttributeList( + c.startupInfo.lpAttributeList, + procThreadAttributePseudoconsole, + *c.hpCon, + unsafe.Sizeof(*c.hpCon)) + if err != nil { + return fmt.Errorf("failed to update proc thread attributes attributes for conpty usage: %v", err) + } + + return +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/doc.go b/vendor/github.com/ActiveState/termtest/conpty/doc.go new file mode 100644 index 0000000000..b423fb62cc --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/doc.go @@ -0,0 +1,11 @@ +// Copyright 2020 ActiveState Software. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// Package conpty provides functions for creating a process attached to a +// ConPTY pseudo-terminal. This allows the process to call console specific +// API functions without an actual terminal being present. +// +// The concept is best explained in this blog post: +// https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ +package conpty diff --git a/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go b/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go new file mode 100644 index 0000000000..6d0777054d --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go @@ -0,0 +1,161 @@ +// Copyright 2009 The Go Authors. All rights reserved. + +// This file has copies of unexported functions form the go source code, +// hence the above copyright message + +package conpty + +import ( + "os" + "strings" + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +// makeCmdLine builds a command line out of args by escaping "special" +// characters and joining the arguments with spaces. +func makeCmdLine(args []string) string { + var s string + for _, v := range args { + if s != "" { + s += " " + } + s += windows.EscapeArg(v) + } + return s +} + +func isSlash(c uint8) bool { + return c == '\\' || c == '/' +} + +func normalizeDir(dir string) (name string, err error) { + ndir, err := syscall.FullPath(dir) + if err != nil { + return "", err + } + if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) { + // dir cannot have \\server\share\path form + return "", syscall.EINVAL + } + return ndir, nil +} + +func volToUpper(ch int) int { + if 'a' <= ch && ch <= 'z' { + ch += 'A' - 'a' + } + return ch +} + +func joinExeDirAndFName(dir, p string) (name string, err error) { + if len(p) == 0 { + return "", syscall.EINVAL + } + if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) { + // \\server\share\path form + return p, nil + } + if len(p) > 1 && p[1] == ':' { + // has drive letter + if len(p) == 2 { + return "", syscall.EINVAL + } + if isSlash(p[2]) { + return p, nil + } else { + d, err := normalizeDir(dir) + if err != nil { + return "", err + } + if volToUpper(int(p[0])) == volToUpper(int(d[0])) { + return syscall.FullPath(d + "\\" + p[2:]) + } else { + return syscall.FullPath(p) + } + } + } else { + // no drive letter + d, err := normalizeDir(dir) + if err != nil { + return "", err + } + if isSlash(p[0]) { + return windows.FullPath(d[:2] + p) + } else { + return windows.FullPath(d + "\\" + p) + } + } +} + +// createEnvBlock converts an array of environment strings into +// the representation required by CreateProcess: a sequence of NUL +// terminated strings followed by a nil. +// Last bytes are two UCS-2 NULs, or four NUL bytes. +func createEnvBlock(envv []string) *uint16 { + if len(envv) == 0 { + return &utf16.Encode([]rune("\x00\x00"))[0] + } + length := 0 + for _, s := range envv { + length += len(s) + 1 + } + length += 1 + + b := make([]byte, length) + i := 0 + for _, s := range envv { + l := len(s) + copy(b[i:i+l], []byte(s)) + copy(b[i+l:i+l+1], []byte{0}) + i = i + l + 1 + } + copy(b[i:i+1], []byte{0}) + + return &utf16.Encode([]rune(string(b)))[0] +} + +// dedupEnvCase is dedupEnv with a case option for testing. +// If caseInsensitive is true, the case of keys is ignored. +func dedupEnvCase(caseInsensitive bool, env []string) []string { + out := make([]string, 0, len(env)) + saw := make(map[string]int, len(env)) // key => index into out + for _, kv := range env { + eq := strings.Index(kv, "=") + if eq < 0 { + out = append(out, kv) + continue + } + k := kv[:eq] + if caseInsensitive { + k = strings.ToLower(k) + } + if dupIdx, isDup := saw[k]; isDup { + out[dupIdx] = kv + continue + } + saw[k] = len(out) + out = append(out, kv) + } + return out +} + +// addCriticalEnv adds any critical environment variables that are required +// (or at least almost always required) on the operating system. +// Currently this is only used for Windows. +func addCriticalEnv(env []string) []string { + for _, kv := range env { + eq := strings.Index(kv, "=") + if eq < 0 { + continue + } + k := kv[:eq] + if strings.EqualFold(k, "SYSTEMROOT") { + // We already have it. + return env + } + } + return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/go.mod b/vendor/github.com/ActiveState/termtest/conpty/go.mod new file mode 100644 index 0000000000..67bb0a5f81 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/go.mod @@ -0,0 +1,8 @@ +module github.com/ActiveState/termtest/conpty + +go 1.12 + +require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 + golang.org/x/sys v0.0.0-20200428200454-593003d681fa +) diff --git a/vendor/github.com/ActiveState/termtest/conpty/go.sum b/vendor/github.com/ActiveState/termtest/conpty/go.sum new file mode 100644 index 0000000000..c1c7bf67bf --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/go.sum @@ -0,0 +1,4 @@ +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= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go b/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go new file mode 100644 index 0000000000..375043114f --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go @@ -0,0 +1,112 @@ +// Copyright 2020 ActiveState Software. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package conpty + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +// load some windows system procedures + +var ( + kernel32 = windows.NewLazySystemDLL("kernel32.dll") + procResizePseudoConsole = kernel32.NewProc("ResizePseudoConsole") + procCreatePseudoConsole = kernel32.NewProc("CreatePseudoConsole") + procClosePseudoConsole = kernel32.NewProc("ClosePseudoConsole") + procInitializeProcThreadAttributeList = kernel32.NewProc("InitializeProcThreadAttributeList") + procUpdateProcThreadAttribute = kernel32.NewProc("UpdateProcThreadAttribute") + procLocalAlloc = kernel32.NewProc("LocalAlloc") + procDeleteProcThreadAttributeList = kernel32.NewProc("DeleteProcThreadAttributeList") + procCreateProcessW = kernel32.NewProc("CreateProcessW") +) + +// an extended version of a process startup info, the attribute list points +// to a pseudo terminal object +type startupInfoEx struct { + startupInfo windows.StartupInfo + lpAttributeList windows.Handle +} + +// constant used in CreateProcessW indicating that extended startup info is present +const extendedStartupinfoPresent uint32 = 0x00080000 + +type procThreadAttribute uintptr + +// windows constant needed during initialization of extended startupinfo +const procThreadAttributePseudoconsole procThreadAttribute = 22 | 0x00020000 // this is the only one we support right now + +func initializeProcThreadAttributeList(attributeList uintptr, attributeCount uint32, listSize *uint64) (err error) { + + if attributeList == 0 { + procInitializeProcThreadAttributeList.Call(0, uintptr(attributeCount), 0, uintptr(unsafe.Pointer(listSize))) + return + } + r1, _, e1 := procInitializeProcThreadAttributeList.Call(attributeList, uintptr(attributeCount), 0, uintptr(unsafe.Pointer(listSize))) + + if r1 == 0 { // boolean FALSE + err = e1 + } + + return +} + +func updateProcThreadAttributeList(attributeList windows.Handle, attribute procThreadAttribute, lpValue windows.Handle, lpSize uintptr) (err error) { + + r1, _, e1 := procUpdateProcThreadAttribute.Call(uintptr(attributeList), 0, uintptr(attribute), uintptr(lpValue), lpSize, 0, 0) + + if r1 == 0 { // boolean FALSE + err = e1 + } + + return +} +func deleteProcThreadAttributeList(handle windows.Handle) (err error) { + r1, _, e1 := procDeleteProcThreadAttributeList.Call(uintptr(handle)) + + if r1 == 0 { // boolean FALSE + err = e1 + } + + return +} + +func localAlloc(size uint64) (ptr windows.Handle, err error) { + r1, _, e1 := procLocalAlloc.Call(uintptr(0x0040), uintptr(size)) + if r1 == 0 { + err = e1 + ptr = windows.InvalidHandle + return + } + ptr = windows.Handle(r1) + return +} + +func createPseudoConsole(consoleSize uintptr, ptyIn windows.Handle, ptyOut windows.Handle, hpCon *windows.Handle) (err error) { + r1, _, e1 := procCreatePseudoConsole.Call(consoleSize, uintptr(ptyIn), uintptr(ptyOut), 0, uintptr(unsafe.Pointer(hpCon))) + + if r1 != 0 { // !S_OK + err = e1 + } + return +} + +func resizePseudoConsole(handle windows.Handle, consoleSize uintptr) (err error) { + r1, _, e1 := procResizePseudoConsole.Call(uintptr(handle), consoleSize) + if r1 != 0 { // !S_OK + err = e1 + } + return +} + +func closePseudoConsole(handle windows.Handle) (err error) { + r1, _, e1 := procClosePseudoConsole.Call(uintptr(handle)) + if r1 == 0 { + err = e1 + } + + return +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/term_other.go b/vendor/github.com/ActiveState/termtest/conpty/term_other.go new file mode 100644 index 0000000000..daef1c0792 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/term_other.go @@ -0,0 +1,7 @@ +// +build !windows + +package conpty + +func InitTerminal(_ bool) (func(), error) { + return func() {}, nil +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/term_windows.go b/vendor/github.com/ActiveState/termtest/conpty/term_windows.go new file mode 100644 index 0000000000..df091b5bb6 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/term_windows.go @@ -0,0 +1,61 @@ +// +build windows + +package conpty + +import ( + "fmt" + "log" + "syscall" + + "github.com/Azure/go-ansiterm/winterm" +) + +func InitTerminal(disableNewlineAutoReturn bool) (func(), error) { + stdoutFd := int(syscall.Stdout) + + // fmt.Printf("file descriptors <%d >%d\n", stdinFd, stdoutFd) + + oldOutMode, err := winterm.GetConsoleMode(uintptr(stdoutFd)) + if err != nil { + return func() {}, fmt.Errorf("failed to retrieve stdout mode: %w", err) + } + + // fmt.Printf("old modes: <%d >%d\n", oldInMode, oldOutMode) + newOutMode := oldOutMode | winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING + if disableNewlineAutoReturn { + newOutMode |= winterm.DISABLE_NEWLINE_AUTO_RETURN + } + + err = winterm.SetConsoleMode(uintptr(stdoutFd), newOutMode) + if err != nil { + return func() {}, fmt.Errorf("failed to set stdout mode: %w", err) + } + + // dump(uintptr(stdoutFd)) + return func() { + err = winterm.SetConsoleMode(uintptr(stdoutFd), oldOutMode) + if err != nil { + log.Fatalf("Failed to reset output terminal mode to %d: %v\n", oldOutMode, err) + } + }, nil +} + +func dump(fd uintptr) { + fmt.Printf("FD=%d\n", fd) + modes, err := winterm.GetConsoleMode(fd) + if err != nil { + panic(err) + } + + fmt.Printf("ENABLE_ECHO_INPUT=%d, ENABLE_PROCESSED_INPUT=%d ENABLE_LINE_INPUT=%d\n", + modes&winterm.ENABLE_ECHO_INPUT, + modes&winterm.ENABLE_PROCESSED_INPUT, + modes&winterm.ENABLE_LINE_INPUT) + fmt.Printf("ENABLE_WINDOW_INPUT=%d, ENABLE_MOUSE_INPUT=%d\n", + modes&winterm.ENABLE_WINDOW_INPUT, + modes&winterm.ENABLE_MOUSE_INPUT) + fmt.Printf("enableVirtualTerminalInput=%d, enableVirtualTerminalProcessing=%d, disableNewlineAutoReturn=%d\n", + modes&winterm.ENABLE_VIRTUAL_TERMINAL_INPUT, + modes&winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING, + modes&winterm.DISABLE_NEWLINE_AUTO_RETURN) +} diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE new file mode 100644 index 0000000000..e3d9a64d1d --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md new file mode 100644 index 0000000000..261c041e7a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/README.md @@ -0,0 +1,12 @@ +# go-ansiterm + +This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent. + +For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position. + +The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). + +See parser_test.go for examples exercising the state machine and generating appropriate function calls. + +----- +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go new file mode 100644 index 0000000000..96504a33bc --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/constants.go @@ -0,0 +1,188 @@ +package ansiterm + +const LogEnv = "DEBUG_TERMINAL" + +// ANSI constants +// References: +// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm +// -- http://man7.org/linux/man-pages/man4/console_codes.4.html +// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html +// -- http://en.wikipedia.org/wiki/ANSI_escape_code +// -- http://vt100.net/emu/dec_ansi_parser +// -- http://vt100.net/emu/vt500_parser.svg +// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html +// -- http://www.inwap.com/pdp10/ansicode.txt +const ( + // ECMA-48 Set Graphics Rendition + // Note: + // -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved + // -- Fonts could possibly be supported via SetCurrentConsoleFontEx + // -- Windows does not expose the per-window cursor (i.e., caret) blink times + ANSI_SGR_RESET = 0 + ANSI_SGR_BOLD = 1 + ANSI_SGR_DIM = 2 + _ANSI_SGR_ITALIC = 3 + ANSI_SGR_UNDERLINE = 4 + _ANSI_SGR_BLINKSLOW = 5 + _ANSI_SGR_BLINKFAST = 6 + ANSI_SGR_REVERSE = 7 + _ANSI_SGR_INVISIBLE = 8 + _ANSI_SGR_LINETHROUGH = 9 + _ANSI_SGR_FONT_00 = 10 + _ANSI_SGR_FONT_01 = 11 + _ANSI_SGR_FONT_02 = 12 + _ANSI_SGR_FONT_03 = 13 + _ANSI_SGR_FONT_04 = 14 + _ANSI_SGR_FONT_05 = 15 + _ANSI_SGR_FONT_06 = 16 + _ANSI_SGR_FONT_07 = 17 + _ANSI_SGR_FONT_08 = 18 + _ANSI_SGR_FONT_09 = 19 + _ANSI_SGR_FONT_10 = 20 + _ANSI_SGR_DOUBLEUNDERLINE = 21 + ANSI_SGR_BOLD_DIM_OFF = 22 + _ANSI_SGR_ITALIC_OFF = 23 + ANSI_SGR_UNDERLINE_OFF = 24 + _ANSI_SGR_BLINK_OFF = 25 + _ANSI_SGR_RESERVED_00 = 26 + ANSI_SGR_REVERSE_OFF = 27 + _ANSI_SGR_INVISIBLE_OFF = 28 + _ANSI_SGR_LINETHROUGH_OFF = 29 + ANSI_SGR_FOREGROUND_BLACK = 30 + ANSI_SGR_FOREGROUND_RED = 31 + ANSI_SGR_FOREGROUND_GREEN = 32 + ANSI_SGR_FOREGROUND_YELLOW = 33 + ANSI_SGR_FOREGROUND_BLUE = 34 + ANSI_SGR_FOREGROUND_MAGENTA = 35 + ANSI_SGR_FOREGROUND_CYAN = 36 + ANSI_SGR_FOREGROUND_WHITE = 37 + _ANSI_SGR_RESERVED_01 = 38 + ANSI_SGR_FOREGROUND_DEFAULT = 39 + ANSI_SGR_BACKGROUND_BLACK = 40 + ANSI_SGR_BACKGROUND_RED = 41 + ANSI_SGR_BACKGROUND_GREEN = 42 + ANSI_SGR_BACKGROUND_YELLOW = 43 + ANSI_SGR_BACKGROUND_BLUE = 44 + ANSI_SGR_BACKGROUND_MAGENTA = 45 + ANSI_SGR_BACKGROUND_CYAN = 46 + ANSI_SGR_BACKGROUND_WHITE = 47 + _ANSI_SGR_RESERVED_02 = 48 + ANSI_SGR_BACKGROUND_DEFAULT = 49 + // 50 - 65: Unsupported + + ANSI_MAX_CMD_LENGTH = 4096 + + MAX_INPUT_EVENTS = 128 + DEFAULT_WIDTH = 80 + DEFAULT_HEIGHT = 24 + + ANSI_BEL = 0x07 + ANSI_BACKSPACE = 0x08 + ANSI_TAB = 0x09 + ANSI_LINE_FEED = 0x0A + ANSI_VERTICAL_TAB = 0x0B + ANSI_FORM_FEED = 0x0C + ANSI_CARRIAGE_RETURN = 0x0D + ANSI_ESCAPE_PRIMARY = 0x1B + ANSI_ESCAPE_SECONDARY = 0x5B + ANSI_OSC_STRING_ENTRY = 0x5D + ANSI_COMMAND_FIRST = 0x40 + ANSI_COMMAND_LAST = 0x7E + DCS_ENTRY = 0x90 + CSI_ENTRY = 0x9B + OSC_STRING = 0x9D + ANSI_PARAMETER_SEP = ";" + ANSI_CMD_G0 = '(' + ANSI_CMD_G1 = ')' + ANSI_CMD_G2 = '*' + ANSI_CMD_G3 = '+' + ANSI_CMD_DECPNM = '>' + ANSI_CMD_DECPAM = '=' + ANSI_CMD_OSC = ']' + ANSI_CMD_STR_TERM = '\\' + + KEY_CONTROL_PARAM_2 = ";2" + KEY_CONTROL_PARAM_3 = ";3" + KEY_CONTROL_PARAM_4 = ";4" + KEY_CONTROL_PARAM_5 = ";5" + KEY_CONTROL_PARAM_6 = ";6" + KEY_CONTROL_PARAM_7 = ";7" + KEY_CONTROL_PARAM_8 = ";8" + KEY_ESC_CSI = "\x1B[" + KEY_ESC_N = "\x1BN" + KEY_ESC_O = "\x1BO" + + FILL_CHARACTER = ' ' +) + +func getByteRange(start byte, end byte) []byte { + bytes := make([]byte, 0, 32) + for i := start; i <= end; i++ { + bytes = append(bytes, byte(i)) + } + + return bytes +} + +var toGroundBytes = getToGroundBytes() +var executors = getExecuteBytes() + +// SPACE 20+A0 hex Always and everywhere a blank space +// Intermediate 20-2F hex !"#$%&'()*+,-./ +var intermeds = getByteRange(0x20, 0x2F) + +// Parameters 30-3F hex 0123456789:;<=>? +// CSI Parameters 30-39, 3B hex 0123456789; +var csiParams = getByteRange(0x30, 0x3F) + +var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) + +// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ +var upperCase = getByteRange(0x40, 0x5F) + +// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~ +var lowerCase = getByteRange(0x60, 0x7E) + +// Alphabetics 40-7E hex (all of upper and lower case) +var alphabetics = append(upperCase, lowerCase...) + +var printables = getByteRange(0x20, 0x7F) + +var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) +var escapeToGroundBytes = getEscapeToGroundBytes() + +// See http://www.vt100.net/emu/vt500_parser.png for description of the complex +// byte ranges below + +func getEscapeToGroundBytes() []byte { + escapeToGroundBytes := getByteRange(0x30, 0x4F) + escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...) + escapeToGroundBytes = append(escapeToGroundBytes, 0x59) + escapeToGroundBytes = append(escapeToGroundBytes, 0x5A) + escapeToGroundBytes = append(escapeToGroundBytes, 0x5C) + escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...) + return escapeToGroundBytes +} + +func getExecuteBytes() []byte { + executeBytes := getByteRange(0x00, 0x17) + executeBytes = append(executeBytes, 0x19) + executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...) + return executeBytes +} + +func getToGroundBytes() []byte { + groundBytes := []byte{0x18} + groundBytes = append(groundBytes, 0x1A) + groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...) + groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...) + groundBytes = append(groundBytes, 0x99) + groundBytes = append(groundBytes, 0x9A) + groundBytes = append(groundBytes, 0x9C) + return groundBytes +} + +// Delete 7F hex Always and everywhere ignored +// C1 Control 80-9F hex 32 additional control characters +// G1 Displayable A1-FE hex 94 additional displayable characters +// Special A0+FF hex Same as SPACE and DELETE diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go new file mode 100644 index 0000000000..8d66e777c0 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/context.go @@ -0,0 +1,7 @@ +package ansiterm + +type ansiContext struct { + currentChar byte + paramBuffer []byte + interBuffer []byte +} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go new file mode 100644 index 0000000000..bcbe00d0c5 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go @@ -0,0 +1,49 @@ +package ansiterm + +type csiEntryState struct { + baseState +} + +func (csiState csiEntryState) Handle(b byte) (s state, e error) { + csiState.parser.logf("CsiEntry::Handle %#x", b) + + nextState, err := csiState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + return csiState.parser.csiParam, nil + case sliceContains(executors, b): + return csiState, csiState.parser.execute() + } + + return csiState, nil +} + +func (csiState csiEntryState) Transition(s state) error { + csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) + csiState.baseState.Transition(s) + + switch s { + case csiState.parser.ground: + return csiState.parser.csiDispatch() + case csiState.parser.csiParam: + switch { + case sliceContains(csiParams, csiState.parser.context.currentChar): + csiState.parser.collectParam() + case sliceContains(intermeds, csiState.parser.context.currentChar): + csiState.parser.collectInter() + } + } + + return nil +} + +func (csiState csiEntryState) Enter() error { + csiState.parser.clear() + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go new file mode 100644 index 0000000000..7ed5e01c34 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go @@ -0,0 +1,38 @@ +package ansiterm + +type csiParamState struct { + baseState +} + +func (csiState csiParamState) Handle(b byte) (s state, e error) { + csiState.parser.logf("CsiParam::Handle %#x", b) + + nextState, err := csiState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + csiState.parser.collectParam() + return csiState, nil + case sliceContains(executors, b): + return csiState, csiState.parser.execute() + } + + return csiState, nil +} + +func (csiState csiParamState) Transition(s state) error { + csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) + csiState.baseState.Transition(s) + + switch s { + case csiState.parser.ground: + return csiState.parser.csiDispatch() + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go new file mode 100644 index 0000000000..1c719db9e4 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go @@ -0,0 +1,36 @@ +package ansiterm + +type escapeIntermediateState struct { + baseState +} + +func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { + escState.parser.logf("escapeIntermediateState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(intermeds, b): + return escState, escState.parser.collectInter() + case sliceContains(executors, b): + return escState, escState.parser.execute() + case sliceContains(escapeIntermediateToGroundBytes, b): + return escState.parser.ground, nil + } + + return escState, nil +} + +func (escState escapeIntermediateState) Transition(s state) error { + escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) + + switch s { + case escState.parser.ground: + return escState.parser.escDispatch() + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go new file mode 100644 index 0000000000..6390abd231 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go @@ -0,0 +1,47 @@ +package ansiterm + +type escapeState struct { + baseState +} + +func (escState escapeState) Handle(b byte) (s state, e error) { + escState.parser.logf("escapeState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case b == ANSI_ESCAPE_SECONDARY: + return escState.parser.csiEntry, nil + case b == ANSI_OSC_STRING_ENTRY: + return escState.parser.oscString, nil + case sliceContains(executors, b): + return escState, escState.parser.execute() + case sliceContains(escapeToGroundBytes, b): + return escState.parser.ground, nil + case sliceContains(intermeds, b): + return escState.parser.escapeIntermediate, nil + } + + return escState, nil +} + +func (escState escapeState) Transition(s state) error { + escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) + + switch s { + case escState.parser.ground: + return escState.parser.escDispatch() + case escState.parser.escapeIntermediate: + return escState.parser.collectInter() + } + + return nil +} + +func (escState escapeState) Enter() error { + escState.parser.clear() + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go new file mode 100644 index 0000000000..98087b38c2 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/event_handler.go @@ -0,0 +1,90 @@ +package ansiterm + +type AnsiEventHandler interface { + // Print + Print(b byte) error + + // Execute C0 commands + Execute(b byte) error + + // CUrsor Up + CUU(int) error + + // CUrsor Down + CUD(int) error + + // CUrsor Forward + CUF(int) error + + // CUrsor Backward + CUB(int) error + + // Cursor to Next Line + CNL(int) error + + // Cursor to Previous Line + CPL(int) error + + // Cursor Horizontal position Absolute + CHA(int) error + + // Vertical line Position Absolute + VPA(int) error + + // CUrsor Position + CUP(int, int) error + + // Horizontal and Vertical Position (depends on PUM) + HVP(int, int) error + + // Text Cursor Enable Mode + DECTCEM(bool) error + + // Origin Mode + DECOM(bool) error + + // 132 Column Mode + DECCOLM(bool) error + + // Erase in Display + ED(int) error + + // Erase in Line + EL(int) error + + // Insert Line + IL(int) error + + // Delete Line + DL(int) error + + // Insert Character + ICH(int) error + + // Delete Character + DCH(int) error + + // Set Graphics Rendition + SGR([]int) error + + // Pan Down + SU(int) error + + // Pan Up + SD(int) error + + // Device Attributes + DA([]string) error + + // Set Top and Bottom Margins + DECSTBM(int, int) error + + // Index + IND() error + + // Reverse Index + RI() error + + // Flush updates from previous commands + Flush() error +} diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go new file mode 100644 index 0000000000..52451e9469 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/ground_state.go @@ -0,0 +1,24 @@ +package ansiterm + +type groundState struct { + baseState +} + +func (gs groundState) Handle(b byte) (s state, e error) { + gs.parser.context.currentChar = b + + nextState, err := gs.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(printables, b): + return gs, gs.parser.print() + + case sliceContains(executors, b): + return gs, gs.parser.execute() + } + + return gs, nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go new file mode 100644 index 0000000000..593b10ab69 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go @@ -0,0 +1,31 @@ +package ansiterm + +type oscStringState struct { + baseState +} + +func (oscState oscStringState) Handle(b byte) (s state, e error) { + oscState.parser.logf("OscString::Handle %#x", b) + nextState, err := oscState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case isOscStringTerminator(b): + return oscState.parser.ground, nil + } + + return oscState, nil +} + +// See below for OSC string terminators for linux +// http://man7.org/linux/man-pages/man4/console_codes.4.html +func isOscStringTerminator(b byte) bool { + + if b == ANSI_BEL || b == 0x5C { + return true + } + + return false +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go new file mode 100644 index 0000000000..03cec7ada6 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser.go @@ -0,0 +1,151 @@ +package ansiterm + +import ( + "errors" + "log" + "os" +) + +type AnsiParser struct { + currState state + eventHandler AnsiEventHandler + context *ansiContext + csiEntry state + csiParam state + dcsEntry state + escape state + escapeIntermediate state + error state + ground state + oscString state + stateMap []state + + logf func(string, ...interface{}) +} + +type Option func(*AnsiParser) + +func WithLogf(f func(string, ...interface{})) Option { + return func(ap *AnsiParser) { + ap.logf = f + } +} + +func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser { + ap := &AnsiParser{ + eventHandler: evtHandler, + context: &ansiContext{}, + } + for _, o := range opts { + o(ap) + } + + if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" { + logFile, _ := os.Create("ansiParser.log") + logger := log.New(logFile, "", log.LstdFlags) + if ap.logf != nil { + l := ap.logf + ap.logf = func(s string, v ...interface{}) { + l(s, v...) + logger.Printf(s, v...) + } + } else { + ap.logf = logger.Printf + } + } + + if ap.logf == nil { + ap.logf = func(string, ...interface{}) {} + } + + ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}} + ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}} + ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}} + ap.escape = escapeState{baseState{name: "Escape", parser: ap}} + ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}} + ap.error = errorState{baseState{name: "Error", parser: ap}} + ap.ground = groundState{baseState{name: "Ground", parser: ap}} + ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}} + + ap.stateMap = []state{ + ap.csiEntry, + ap.csiParam, + ap.dcsEntry, + ap.escape, + ap.escapeIntermediate, + ap.error, + ap.ground, + ap.oscString, + } + + ap.currState = getState(initialState, ap.stateMap) + + ap.logf("CreateParser: parser %p", ap) + return ap +} + +func getState(name string, states []state) state { + for _, el := range states { + if el.Name() == name { + return el + } + } + + return nil +} + +func (ap *AnsiParser) Parse(bytes []byte) (int, error) { + for i, b := range bytes { + if err := ap.handle(b); err != nil { + return i, err + } + } + + return len(bytes), ap.eventHandler.Flush() +} + +func (ap *AnsiParser) handle(b byte) error { + ap.context.currentChar = b + newState, err := ap.currState.Handle(b) + if err != nil { + return err + } + + if newState == nil { + ap.logf("WARNING: newState is nil") + return errors.New("New state of 'nil' is invalid.") + } + + if newState != ap.currState { + if err := ap.changeState(newState); err != nil { + return err + } + } + + return nil +} + +func (ap *AnsiParser) changeState(newState state) error { + ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name()) + + // Exit old state + if err := ap.currState.Exit(); err != nil { + ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err) + return err + } + + // Perform transition action + if err := ap.currState.Transition(newState); err != nil { + ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err) + return err + } + + // Enter new state + if err := newState.Enter(); err != nil { + ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err) + return err + } + + ap.currState = newState + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go new file mode 100644 index 0000000000..de0a1f9cde --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go @@ -0,0 +1,99 @@ +package ansiterm + +import ( + "strconv" +) + +func parseParams(bytes []byte) ([]string, error) { + paramBuff := make([]byte, 0, 0) + params := []string{} + + for _, v := range bytes { + if v == ';' { + if len(paramBuff) > 0 { + // Completed parameter, append it to the list + s := string(paramBuff) + params = append(params, s) + paramBuff = make([]byte, 0, 0) + } + } else { + paramBuff = append(paramBuff, v) + } + } + + // Last parameter may not be terminated with ';' + if len(paramBuff) > 0 { + s := string(paramBuff) + params = append(params, s) + } + + return params, nil +} + +func parseCmd(context ansiContext) (string, error) { + return string(context.currentChar), nil +} + +func getInt(params []string, dflt int) int { + i := getInts(params, 1, dflt)[0] + return i +} + +func getInts(params []string, minCount int, dflt int) []int { + ints := []int{} + + for _, v := range params { + i, _ := strconv.Atoi(v) + // Zero is mapped to the default value in VT100. + if i == 0 { + i = dflt + } + ints = append(ints, i) + } + + if len(ints) < minCount { + remaining := minCount - len(ints) + for i := 0; i < remaining; i++ { + ints = append(ints, dflt) + } + } + + return ints +} + +func (ap *AnsiParser) modeDispatch(param string, set bool) error { + switch param { + case "?3": + return ap.eventHandler.DECCOLM(set) + case "?6": + return ap.eventHandler.DECOM(set) + case "?25": + return ap.eventHandler.DECTCEM(set) + } + return nil +} + +func (ap *AnsiParser) hDispatch(params []string) error { + if len(params) == 1 { + return ap.modeDispatch(params[0], true) + } + + return nil +} + +func (ap *AnsiParser) lDispatch(params []string) error { + if len(params) == 1 { + return ap.modeDispatch(params[0], false) + } + + return nil +} + +func getEraseParam(params []string) int { + param := getInt(params, 0) + if param < 0 || 3 < param { + param = 0 + } + + return param +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go new file mode 100644 index 0000000000..0bb5e51e9a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go @@ -0,0 +1,119 @@ +package ansiterm + +func (ap *AnsiParser) collectParam() error { + currChar := ap.context.currentChar + ap.logf("collectParam %#x", currChar) + ap.context.paramBuffer = append(ap.context.paramBuffer, currChar) + return nil +} + +func (ap *AnsiParser) collectInter() error { + currChar := ap.context.currentChar + ap.logf("collectInter %#x", currChar) + ap.context.paramBuffer = append(ap.context.interBuffer, currChar) + return nil +} + +func (ap *AnsiParser) escDispatch() error { + cmd, _ := parseCmd(*ap.context) + intermeds := ap.context.interBuffer + ap.logf("escDispatch currentChar: %#x", ap.context.currentChar) + ap.logf("escDispatch: %v(%v)", cmd, intermeds) + + switch cmd { + case "D": // IND + return ap.eventHandler.IND() + case "E": // NEL, equivalent to CRLF + err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN) + if err == nil { + err = ap.eventHandler.Execute(ANSI_LINE_FEED) + } + return err + case "M": // RI + return ap.eventHandler.RI() + } + + return nil +} + +func (ap *AnsiParser) csiDispatch() error { + cmd, _ := parseCmd(*ap.context) + params, _ := parseParams(ap.context.paramBuffer) + ap.logf("Parsed params: %v with length: %d", params, len(params)) + + ap.logf("csiDispatch: %v(%v)", cmd, params) + + switch cmd { + case "@": + return ap.eventHandler.ICH(getInt(params, 1)) + case "A": + return ap.eventHandler.CUU(getInt(params, 1)) + case "B": + return ap.eventHandler.CUD(getInt(params, 1)) + case "C": + return ap.eventHandler.CUF(getInt(params, 1)) + case "D": + return ap.eventHandler.CUB(getInt(params, 1)) + case "E": + return ap.eventHandler.CNL(getInt(params, 1)) + case "F": + return ap.eventHandler.CPL(getInt(params, 1)) + case "G": + return ap.eventHandler.CHA(getInt(params, 1)) + case "H": + ints := getInts(params, 2, 1) + x, y := ints[0], ints[1] + return ap.eventHandler.CUP(x, y) + case "J": + param := getEraseParam(params) + return ap.eventHandler.ED(param) + case "K": + param := getEraseParam(params) + return ap.eventHandler.EL(param) + case "L": + return ap.eventHandler.IL(getInt(params, 1)) + case "M": + return ap.eventHandler.DL(getInt(params, 1)) + case "P": + return ap.eventHandler.DCH(getInt(params, 1)) + case "S": + return ap.eventHandler.SU(getInt(params, 1)) + case "T": + return ap.eventHandler.SD(getInt(params, 1)) + case "c": + return ap.eventHandler.DA(params) + case "d": + return ap.eventHandler.VPA(getInt(params, 1)) + case "f": + ints := getInts(params, 2, 1) + x, y := ints[0], ints[1] + return ap.eventHandler.HVP(x, y) + case "h": + return ap.hDispatch(params) + case "l": + return ap.lDispatch(params) + case "m": + return ap.eventHandler.SGR(getInts(params, 1, 0)) + case "r": + ints := getInts(params, 2, 1) + top, bottom := ints[0], ints[1] + return ap.eventHandler.DECSTBM(top, bottom) + default: + ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context) + return nil + } + +} + +func (ap *AnsiParser) print() error { + return ap.eventHandler.Print(ap.context.currentChar) +} + +func (ap *AnsiParser) clear() error { + ap.context = &ansiContext{} + return nil +} + +func (ap *AnsiParser) execute() error { + return ap.eventHandler.Execute(ap.context.currentChar) +} diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go new file mode 100644 index 0000000000..f2ea1fcd12 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/states.go @@ -0,0 +1,71 @@ +package ansiterm + +type stateID int + +type state interface { + Enter() error + Exit() error + Handle(byte) (state, error) + Name() string + Transition(state) error +} + +type baseState struct { + name string + parser *AnsiParser +} + +func (base baseState) Enter() error { + return nil +} + +func (base baseState) Exit() error { + return nil +} + +func (base baseState) Handle(b byte) (s state, e error) { + + switch { + case b == CSI_ENTRY: + return base.parser.csiEntry, nil + case b == DCS_ENTRY: + return base.parser.dcsEntry, nil + case b == ANSI_ESCAPE_PRIMARY: + return base.parser.escape, nil + case b == OSC_STRING: + return base.parser.oscString, nil + case sliceContains(toGroundBytes, b): + return base.parser.ground, nil + } + + return nil, nil +} + +func (base baseState) Name() string { + return base.name +} + +func (base baseState) Transition(s state) error { + if s == base.parser.ground { + execBytes := []byte{0x18} + execBytes = append(execBytes, 0x1A) + execBytes = append(execBytes, getByteRange(0x80, 0x8F)...) + execBytes = append(execBytes, getByteRange(0x91, 0x97)...) + execBytes = append(execBytes, 0x99) + execBytes = append(execBytes, 0x9A) + + if sliceContains(execBytes, base.parser.context.currentChar) { + return base.parser.execute() + } + } + + return nil +} + +type dcsEntryState struct { + baseState +} + +type errorState struct { + baseState +} diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go new file mode 100644 index 0000000000..392114493a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/utilities.go @@ -0,0 +1,21 @@ +package ansiterm + +import ( + "strconv" +) + +func sliceContains(bytes []byte, b byte) bool { + for _, v := range bytes { + if v == b { + return true + } + } + + return false +} + +func convertBytesToInteger(bytes []byte) int { + s := string(bytes) + i, _ := strconv.Atoi(s) + return i +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go new file mode 100644 index 0000000000..a673279726 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go @@ -0,0 +1,182 @@ +// +build windows + +package winterm + +import ( + "fmt" + "os" + "strconv" + "strings" + "syscall" + + "github.com/Azure/go-ansiterm" +) + +// Windows keyboard constants +// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx. +const ( + VK_PRIOR = 0x21 // PAGE UP key + VK_NEXT = 0x22 // PAGE DOWN key + VK_END = 0x23 // END key + VK_HOME = 0x24 // HOME key + VK_LEFT = 0x25 // LEFT ARROW key + VK_UP = 0x26 // UP ARROW key + VK_RIGHT = 0x27 // RIGHT ARROW key + VK_DOWN = 0x28 // DOWN ARROW key + VK_SELECT = 0x29 // SELECT key + VK_PRINT = 0x2A // PRINT key + VK_EXECUTE = 0x2B // EXECUTE key + VK_SNAPSHOT = 0x2C // PRINT SCREEN key + VK_INSERT = 0x2D // INS key + VK_DELETE = 0x2E // DEL key + VK_HELP = 0x2F // HELP key + VK_F1 = 0x70 // F1 key + VK_F2 = 0x71 // F2 key + VK_F3 = 0x72 // F3 key + VK_F4 = 0x73 // F4 key + VK_F5 = 0x74 // F5 key + VK_F6 = 0x75 // F6 key + VK_F7 = 0x76 // F7 key + VK_F8 = 0x77 // F8 key + VK_F9 = 0x78 // F9 key + VK_F10 = 0x79 // F10 key + VK_F11 = 0x7A // F11 key + VK_F12 = 0x7B // F12 key + + RIGHT_ALT_PRESSED = 0x0001 + LEFT_ALT_PRESSED = 0x0002 + RIGHT_CTRL_PRESSED = 0x0004 + LEFT_CTRL_PRESSED = 0x0008 + SHIFT_PRESSED = 0x0010 + NUMLOCK_ON = 0x0020 + SCROLLLOCK_ON = 0x0040 + CAPSLOCK_ON = 0x0080 + ENHANCED_KEY = 0x0100 +) + +type ansiCommand struct { + CommandBytes []byte + Command string + Parameters []string + IsSpecial bool +} + +func newAnsiCommand(command []byte) *ansiCommand { + + if isCharacterSelectionCmdChar(command[1]) { + // Is Character Set Selection commands + return &ansiCommand{ + CommandBytes: command, + Command: string(command), + IsSpecial: true, + } + } + + // last char is command character + lastCharIndex := len(command) - 1 + + ac := &ansiCommand{ + CommandBytes: command, + Command: string(command[lastCharIndex]), + IsSpecial: false, + } + + // more than a single escape + if lastCharIndex != 0 { + start := 1 + // skip if double char escape sequence + if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { + start++ + } + // convert this to GetNextParam method + ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) + } + + return ac +} + +func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { + if index < 0 || index >= len(ac.Parameters) { + return defaultValue + } + + param, err := strconv.ParseInt(ac.Parameters[index], 10, 16) + if err != nil { + return defaultValue + } + + return int16(param) +} + +func (ac *ansiCommand) String() string { + return fmt.Sprintf("0x%v \"%v\" (\"%v\")", + bytesToHex(ac.CommandBytes), + ac.Command, + strings.Join(ac.Parameters, "\",\"")) +} + +// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands. +// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. +func isAnsiCommandChar(b byte) bool { + switch { + case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: + return true + case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: + // non-CSI escape sequence terminator + return true + case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: + // String escape sequence terminator + return true + } + return false +} + +func isXtermOscSequence(command []byte, current byte) bool { + return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) +} + +func isCharacterSelectionCmdChar(b byte) bool { + return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) +} + +// bytesToHex converts a slice of bytes to a human-readable string. +func bytesToHex(b []byte) string { + hex := make([]string, len(b)) + for i, ch := range b { + hex[i] = fmt.Sprintf("%X", ch) + } + return strings.Join(hex, "") +} + +// ensureInRange adjusts the passed value, if necessary, to ensure it is within +// the passed min / max range. +func ensureInRange(n int16, min int16, max int16) int16 { + if n < min { + return min + } else if n > max { + return max + } else { + return n + } +} + +func GetStdFile(nFile int) (*os.File, uintptr) { + var file *os.File + switch nFile { + case syscall.STD_INPUT_HANDLE: + file = os.Stdin + case syscall.STD_OUTPUT_HANDLE: + file = os.Stdout + case syscall.STD_ERROR_HANDLE: + file = os.Stderr + default: + panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile)) + } + + fd, err := syscall.GetStdHandle(nFile) + if err != nil { + panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err)) + } + + return file, uintptr(fd) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go new file mode 100644 index 0000000000..6055e33b91 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/api.go @@ -0,0 +1,327 @@ +// +build windows + +package winterm + +import ( + "fmt" + "syscall" + "unsafe" +) + +//=========================================================================================================== +// IMPORTANT NOTE: +// +// The methods below make extensive use of the "unsafe" package to obtain the required pointers. +// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack +// variables) the pointers reference *before* the API completes. +// +// As a result, in those cases, the code must hint that the variables remain in active by invoking the +// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer +// require unsafe pointers. +// +// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform +// the garbage collector the variables remain in use if: +// +// -- The value is not a pointer (e.g., int32, struct) +// -- The value is not referenced by the method after passing the pointer to Windows +// +// See http://golang.org/doc/go1.3. +//=========================================================================================================== + +var ( + kernel32DLL = syscall.NewLazyDLL("kernel32.dll") + + getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo") + setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo") + setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition") + setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode") + getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") + setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize") + scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA") + setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") + setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo") + writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW") + readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW") + waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject") +) + +// Windows Console constants +const ( + // Console modes + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. + ENABLE_PROCESSED_INPUT = 0x0001 + ENABLE_LINE_INPUT = 0x0002 + ENABLE_ECHO_INPUT = 0x0004 + ENABLE_WINDOW_INPUT = 0x0008 + ENABLE_MOUSE_INPUT = 0x0010 + ENABLE_INSERT_MODE = 0x0020 + ENABLE_QUICK_EDIT_MODE = 0x0040 + ENABLE_EXTENDED_FLAGS = 0x0080 + ENABLE_AUTO_POSITION = 0x0100 + ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200 + + ENABLE_PROCESSED_OUTPUT = 0x0001 + ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + DISABLE_NEWLINE_AUTO_RETURN = 0x0008 + ENABLE_LVB_GRID_WORLDWIDE = 0x0010 + + // Character attributes + // Note: + // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). + // Clearing all foreground or background colors results in black; setting all creates white. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. + FOREGROUND_BLUE uint16 = 0x0001 + FOREGROUND_GREEN uint16 = 0x0002 + FOREGROUND_RED uint16 = 0x0004 + FOREGROUND_INTENSITY uint16 = 0x0008 + FOREGROUND_MASK uint16 = 0x000F + + BACKGROUND_BLUE uint16 = 0x0010 + BACKGROUND_GREEN uint16 = 0x0020 + BACKGROUND_RED uint16 = 0x0040 + BACKGROUND_INTENSITY uint16 = 0x0080 + BACKGROUND_MASK uint16 = 0x00F0 + + COMMON_LVB_MASK uint16 = 0xFF00 + COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000 + COMMON_LVB_UNDERSCORE uint16 = 0x8000 + + // Input event types + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. + KEY_EVENT = 0x0001 + MOUSE_EVENT = 0x0002 + WINDOW_BUFFER_SIZE_EVENT = 0x0004 + MENU_EVENT = 0x0008 + FOCUS_EVENT = 0x0010 + + // WaitForSingleObject return codes + WAIT_ABANDONED = 0x00000080 + WAIT_FAILED = 0xFFFFFFFF + WAIT_SIGNALED = 0x0000000 + WAIT_TIMEOUT = 0x00000102 + + // WaitForSingleObject wait duration + WAIT_INFINITE = 0xFFFFFFFF + WAIT_ONE_SECOND = 1000 + WAIT_HALF_SECOND = 500 + WAIT_QUARTER_SECOND = 250 +) + +// Windows API Console types +// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD) +// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment +type ( + CHAR_INFO struct { + UnicodeChar uint16 + Attributes uint16 + } + + CONSOLE_CURSOR_INFO struct { + Size uint32 + Visible int32 + } + + CONSOLE_SCREEN_BUFFER_INFO struct { + Size COORD + CursorPosition COORD + Attributes uint16 + Window SMALL_RECT + MaximumWindowSize COORD + } + + COORD struct { + X int16 + Y int16 + } + + SMALL_RECT struct { + Left int16 + Top int16 + Right int16 + Bottom int16 + } + + // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. + INPUT_RECORD struct { + EventType uint16 + KeyEvent KEY_EVENT_RECORD + } + + KEY_EVENT_RECORD struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + UnicodeChar uint16 + ControlKeyState uint32 + } + + WINDOW_BUFFER_SIZE struct { + Size COORD + } +) + +// boolToBOOL converts a Go bool into a Windows int32. +func boolToBOOL(f bool) int32 { + if f { + return int32(1) + } else { + return int32(0) + } +} + +// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx. +func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { + r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) + return checkError(r1, r2, err) +} + +// SetConsoleCursorInfo sets the size and visiblity of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx. +func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { + r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) + return checkError(r1, r2, err) +} + +// SetConsoleCursorPosition location of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx. +func SetConsoleCursorPosition(handle uintptr, coord COORD) error { + r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord)) + use(coord) + return checkError(r1, r2, err) +} + +// GetConsoleMode gets the console mode for given file descriptor +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx. +func GetConsoleMode(handle uintptr) (mode uint32, err error) { + err = syscall.GetConsoleMode(syscall.Handle(handle), &mode) + return mode, err +} + +// SetConsoleMode sets the console mode for given file descriptor +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. +func SetConsoleMode(handle uintptr, mode uint32) error { + r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0) + use(mode) + return checkError(r1, r2, err) +} + +// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx. +func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { + info := CONSOLE_SCREEN_BUFFER_INFO{} + err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)) + if err != nil { + return nil, err + } + return &info, nil +} + +func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error { + r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char))) + use(scrollRect) + use(clipRect) + use(destOrigin) + use(char) + return checkError(r1, r2, err) +} + +// SetConsoleScreenBufferSize sets the size of the console screen buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx. +func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error { + r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord)) + use(coord) + return checkError(r1, r2, err) +} + +// SetConsoleTextAttribute sets the attributes of characters written to the +// console screen buffer by the WriteFile or WriteConsole function. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. +func SetConsoleTextAttribute(handle uintptr, attribute uint16) error { + r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0) + use(attribute) + return checkError(r1, r2, err) +} + +// SetConsoleWindowInfo sets the size and position of the console screen buffer's window. +// Note that the size and location must be within and no larger than the backing console screen buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx. +func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error { + r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect))) + use(isAbsolute) + use(rect) + return checkError(r1, r2, err) +} + +// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx. +func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error { + r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion))) + use(buffer) + use(bufferSize) + use(bufferCoord) + return checkError(r1, r2, err) +} + +// ReadConsoleInput reads (and removes) data from the console input buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx. +func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error { + r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count))) + use(buffer) + return checkError(r1, r2, err) +} + +// WaitForSingleObject waits for the passed handle to be signaled. +// It returns true if the handle was signaled; false otherwise. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx. +func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) { + r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait))) + switch r1 { + case WAIT_ABANDONED, WAIT_TIMEOUT: + return false, nil + case WAIT_SIGNALED: + return true, nil + } + use(msWait) + return false, err +} + +// String helpers +func (info CONSOLE_SCREEN_BUFFER_INFO) String() string { + return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize) +} + +func (coord COORD) String() string { + return fmt.Sprintf("%v,%v", coord.X, coord.Y) +} + +func (rect SMALL_RECT) String() string { + return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom) +} + +// checkError evaluates the results of a Windows API call and returns the error if it failed. +func checkError(r1, r2 uintptr, err error) error { + // Windows APIs return non-zero to indicate success + if r1 != 0 { + return nil + } + + // Return the error if provided, otherwise default to EINVAL + if err != nil { + return err + } + return syscall.EINVAL +} + +// coordToPointer converts a COORD into a uintptr (by fooling the type system). +func coordToPointer(c COORD) uintptr { + // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass. + return uintptr(*((*uint32)(unsafe.Pointer(&c)))) +} + +// use is a no-op, but the compiler cannot see that it is. +// Calling use(p) ensures that p is kept live until that point. +func use(p interface{}) {} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go new file mode 100644 index 0000000000..cbec8f728f --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go @@ -0,0 +1,100 @@ +// +build windows + +package winterm + +import "github.com/Azure/go-ansiterm" + +const ( + FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE + BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE +) + +// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the +// request represented by the passed ANSI mode. +func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) { + switch ansiMode { + + // Mode styles + case ansiterm.ANSI_SGR_BOLD: + windowsMode = windowsMode | FOREGROUND_INTENSITY + + case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF: + windowsMode &^= FOREGROUND_INTENSITY + + case ansiterm.ANSI_SGR_UNDERLINE: + windowsMode = windowsMode | COMMON_LVB_UNDERSCORE + + case ansiterm.ANSI_SGR_REVERSE: + inverted = true + + case ansiterm.ANSI_SGR_REVERSE_OFF: + inverted = false + + case ansiterm.ANSI_SGR_UNDERLINE_OFF: + windowsMode &^= COMMON_LVB_UNDERSCORE + + // Foreground colors + case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT: + windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK) + + case ansiterm.ANSI_SGR_FOREGROUND_BLACK: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) + + case ansiterm.ANSI_SGR_FOREGROUND_RED: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED + + case ansiterm.ANSI_SGR_FOREGROUND_GREEN: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN + + case ansiterm.ANSI_SGR_FOREGROUND_YELLOW: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN + + case ansiterm.ANSI_SGR_FOREGROUND_BLUE: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_CYAN: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_WHITE: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE + + // Background colors + case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT: + // Black with no intensity + windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK) + + case ansiterm.ANSI_SGR_BACKGROUND_BLACK: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) + + case ansiterm.ANSI_SGR_BACKGROUND_RED: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED + + case ansiterm.ANSI_SGR_BACKGROUND_GREEN: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN + + case ansiterm.ANSI_SGR_BACKGROUND_YELLOW: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN + + case ansiterm.ANSI_SGR_BACKGROUND_BLUE: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_CYAN: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_WHITE: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE + } + + return windowsMode, inverted +} + +// invertAttributes inverts the foreground and background colors of a Windows attributes value +func invertAttributes(windowsMode uint16) uint16 { + return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go new file mode 100644 index 0000000000..3ee06ea728 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go @@ -0,0 +1,101 @@ +// +build windows + +package winterm + +const ( + horizontal = iota + vertical +) + +func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { + if h.originMode { + sr := h.effectiveSr(info.Window) + return SMALL_RECT{ + Top: sr.top, + Bottom: sr.bottom, + Left: 0, + Right: info.Size.X - 1, + } + } else { + return SMALL_RECT{ + Top: info.Window.Top, + Bottom: info.Window.Bottom, + Left: 0, + Right: info.Size.X - 1, + } + } +} + +// setCursorPosition sets the cursor to the specified position, bounded to the screen size +func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { + position.X = ensureInRange(position.X, window.Left, window.Right) + position.Y = ensureInRange(position.Y, window.Top, window.Bottom) + err := SetConsoleCursorPosition(h.fd, position) + if err != nil { + return err + } + h.logf("Cursor position set: (%d, %d)", position.X, position.Y) + return err +} + +func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error { + return h.moveCursor(vertical, param) +} + +func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error { + return h.moveCursor(horizontal, param) +} + +func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + switch moveMode { + case horizontal: + position.X += int16(param) + case vertical: + position.Y += int16(param) + } + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) moveCursorLine(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + position.X = 0 + position.Y += int16(param) + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + position.X = int16(param) - 1 + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go new file mode 100644 index 0000000000..244b5fa25e --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go @@ -0,0 +1,84 @@ +// +build windows + +package winterm + +import "github.com/Azure/go-ansiterm" + +func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error { + // Ignore an invalid (negative area) request + if toCoord.Y < fromCoord.Y { + return nil + } + + var err error + + var coordStart = COORD{} + var coordEnd = COORD{} + + xCurrent, yCurrent := fromCoord.X, fromCoord.Y + xEnd, yEnd := toCoord.X, toCoord.Y + + // Clear any partial initial line + if xCurrent > 0 { + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yCurrent + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + xCurrent = 0 + yCurrent += 1 + } + + // Clear intervening rectangular section + if yCurrent < yEnd { + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yEnd-1 + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + xCurrent = 0 + yCurrent = yEnd + } + + // Clear remaining partial ending line + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yEnd + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error { + region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X} + width := toCoord.X - fromCoord.X + 1 + height := toCoord.Y - fromCoord.Y + 1 + size := uint32(width) * uint32(height) + + if size <= 0 { + return nil + } + + buffer := make([]CHAR_INFO, size) + + char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes} + for i := 0; i < int(size); i++ { + buffer[i] = char + } + + err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go new file mode 100644 index 0000000000..2d27fa1d02 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go @@ -0,0 +1,118 @@ +// +build windows + +package winterm + +// effectiveSr gets the current effective scroll region in buffer coordinates +func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { + top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom) + bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) + if top >= bottom { + top = window.Top + bottom = window.Bottom + } + return scrollRegion{top: top, bottom: bottom} +} + +func (h *windowsAnsiEventHandler) scrollUp(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + sr := h.effectiveSr(info.Window) + return h.scroll(param, sr, info) +} + +func (h *windowsAnsiEventHandler) scrollDown(param int) error { + return h.scrollUp(-param) +} + +func (h *windowsAnsiEventHandler) deleteLines(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + start := info.CursorPosition.Y + sr := h.effectiveSr(info.Window) + // Lines cannot be inserted or deleted outside the scrolling region. + if start >= sr.top && start <= sr.bottom { + sr.top = start + return h.scroll(param, sr, info) + } else { + return nil + } +} + +func (h *windowsAnsiEventHandler) insertLines(param int) error { + return h.deleteLines(-param) +} + +// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates. +func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { + h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom) + h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom) + + // Copy from and clip to the scroll region (full buffer width) + scrollRect := SMALL_RECT{ + Top: sr.top, + Bottom: sr.bottom, + Left: 0, + Right: info.Size.X - 1, + } + + // Origin to which area should be copied + destOrigin := COORD{ + X: 0, + Y: sr.top - int16(param), + } + + char := CHAR_INFO{ + UnicodeChar: ' ', + Attributes: h.attributes, + } + + if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { + return err + } + return nil +} + +func (h *windowsAnsiEventHandler) deleteCharacters(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + return h.scrollLine(param, info.CursorPosition, info) +} + +func (h *windowsAnsiEventHandler) insertCharacters(param int) error { + return h.deleteCharacters(-param) +} + +// scrollLine scrolls a line horizontally starting at the provided position by a number of columns. +func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { + // Copy from and clip to the scroll region (full buffer width) + scrollRect := SMALL_RECT{ + Top: position.Y, + Bottom: position.Y, + Left: position.X, + Right: info.Size.X - 1, + } + + // Origin to which area should be copied + destOrigin := COORD{ + X: position.X - int16(columns), + Y: position.Y, + } + + char := CHAR_INFO{ + UnicodeChar: ' ', + Attributes: h.attributes, + } + + if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go new file mode 100644 index 0000000000..afa7635d77 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go @@ -0,0 +1,9 @@ +// +build windows + +package winterm + +// AddInRange increments a value by the passed quantity while ensuring the values +// always remain within the supplied min / max range. +func addInRange(n int16, increment int16, min int16, max int16) int16 { + return ensureInRange(n+increment, min, max) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go new file mode 100644 index 0000000000..2d40fb75ad --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go @@ -0,0 +1,743 @@ +// +build windows + +package winterm + +import ( + "bytes" + "log" + "os" + "strconv" + + "github.com/Azure/go-ansiterm" +) + +type windowsAnsiEventHandler struct { + fd uintptr + file *os.File + infoReset *CONSOLE_SCREEN_BUFFER_INFO + sr scrollRegion + buffer bytes.Buffer + attributes uint16 + inverted bool + wrapNext bool + drewMarginByte bool + originMode bool + marginByte byte + curInfo *CONSOLE_SCREEN_BUFFER_INFO + curPos COORD + logf func(string, ...interface{}) +} + +type Option func(*windowsAnsiEventHandler) + +func WithLogf(f func(string, ...interface{})) Option { + return func(w *windowsAnsiEventHandler) { + w.logf = f + } +} + +func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler { + infoReset, err := GetConsoleScreenBufferInfo(fd) + if err != nil { + return nil + } + + h := &windowsAnsiEventHandler{ + fd: fd, + file: file, + infoReset: infoReset, + attributes: infoReset.Attributes, + } + for _, o := range opts { + o(h) + } + + if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { + logFile, _ := os.Create("winEventHandler.log") + logger := log.New(logFile, "", log.LstdFlags) + if h.logf != nil { + l := h.logf + h.logf = func(s string, v ...interface{}) { + l(s, v...) + logger.Printf(s, v...) + } + } else { + h.logf = logger.Printf + } + } + + if h.logf == nil { + h.logf = func(string, ...interface{}) {} + } + + return h +} + +type scrollRegion struct { + top int16 + bottom int16 +} + +// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the +// current cursor position and scroll region settings, in which case it returns +// true. If no special handling is necessary, then it does nothing and returns +// false. +// +// In the false case, the caller should ensure that a carriage return +// and line feed are inserted or that the text is otherwise wrapped. +func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { + if h.wrapNext { + if err := h.Flush(); err != nil { + return false, err + } + h.clearWrap() + } + pos, info, err := h.getCurrentInfo() + if err != nil { + return false, err + } + sr := h.effectiveSr(info.Window) + if pos.Y == sr.bottom { + // Scrolling is necessary. Let Windows automatically scroll if the scrolling region + // is the full window. + if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom { + if includeCR { + pos.X = 0 + h.updatePos(pos) + } + return false, nil + } + + // A custom scroll region is active. Scroll the window manually to simulate + // the LF. + if err := h.Flush(); err != nil { + return false, err + } + h.logf("Simulating LF inside scroll region") + if err := h.scrollUp(1); err != nil { + return false, err + } + if includeCR { + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return false, err + } + } + return true, nil + + } else if pos.Y < info.Window.Bottom { + // Let Windows handle the LF. + pos.Y++ + if includeCR { + pos.X = 0 + } + h.updatePos(pos) + return false, nil + } else { + // The cursor is at the bottom of the screen but outside the scroll + // region. Skip the LF. + h.logf("Simulating LF outside scroll region") + if includeCR { + if err := h.Flush(); err != nil { + return false, err + } + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return false, err + } + } + return true, nil + } +} + +// executeLF executes a LF without a CR. +func (h *windowsAnsiEventHandler) executeLF() error { + handled, err := h.simulateLF(false) + if err != nil { + return err + } + if !handled { + // Windows LF will reset the cursor column position. Write the LF + // and restore the cursor position. + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) + if pos.X != 0 { + if err := h.Flush(); err != nil { + return err + } + h.logf("Resetting cursor position for LF without CR") + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + } + } + return nil +} + +func (h *windowsAnsiEventHandler) Print(b byte) error { + if h.wrapNext { + h.buffer.WriteByte(h.marginByte) + h.clearWrap() + if _, err := h.simulateLF(true); err != nil { + return err + } + } + pos, info, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X == info.Size.X-1 { + h.wrapNext = true + h.marginByte = b + } else { + pos.X++ + h.updatePos(pos) + h.buffer.WriteByte(b) + } + return nil +} + +func (h *windowsAnsiEventHandler) Execute(b byte) error { + switch b { + case ansiterm.ANSI_TAB: + h.logf("Execute(TAB)") + // Move to the next tab stop, but preserve auto-wrap if already set. + if !h.wrapNext { + pos, info, err := h.getCurrentInfo() + if err != nil { + return err + } + pos.X = (pos.X + 8) - pos.X%8 + if pos.X >= info.Size.X { + pos.X = info.Size.X - 1 + } + if err := h.Flush(); err != nil { + return err + } + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + } + return nil + + case ansiterm.ANSI_BEL: + h.buffer.WriteByte(ansiterm.ANSI_BEL) + return nil + + case ansiterm.ANSI_BACKSPACE: + if h.wrapNext { + if err := h.Flush(); err != nil { + return err + } + h.clearWrap() + } + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X > 0 { + pos.X-- + h.updatePos(pos) + h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE) + } + return nil + + case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED: + // Treat as true LF. + return h.executeLF() + + case ansiterm.ANSI_LINE_FEED: + // Simulate a CR and LF for now since there is no way in go-ansiterm + // to tell if the LF should include CR (and more things break when it's + // missing than when it's incorrectly added). + handled, err := h.simulateLF(true) + if handled || err != nil { + return err + } + return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) + + case ansiterm.ANSI_CARRIAGE_RETURN: + if h.wrapNext { + if err := h.Flush(); err != nil { + return err + } + h.clearWrap() + } + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X != 0 { + pos.X = 0 + h.updatePos(pos) + h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN) + } + return nil + + default: + return nil + } +} + +func (h *windowsAnsiEventHandler) CUU(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUU: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorVertical(-param) +} + +func (h *windowsAnsiEventHandler) CUD(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUD: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorVertical(param) +} + +func (h *windowsAnsiEventHandler) CUF(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUF: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorHorizontal(param) +} + +func (h *windowsAnsiEventHandler) CUB(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUB: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorHorizontal(-param) +} + +func (h *windowsAnsiEventHandler) CNL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CNL: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorLine(param) +} + +func (h *windowsAnsiEventHandler) CPL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CPL: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorLine(-param) +} + +func (h *windowsAnsiEventHandler) CHA(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CHA: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorColumn(param) +} + +func (h *windowsAnsiEventHandler) VPA(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("VPA: [[%d]]", param) + h.clearWrap() + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + window := h.getCursorWindow(info) + position := info.CursorPosition + position.Y = window.Top + int16(param) - 1 + return h.setCursorPosition(position, window) +} + +func (h *windowsAnsiEventHandler) CUP(row int, col int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUP: [[%d %d]]", row, col) + h.clearWrap() + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + window := h.getCursorWindow(info) + position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1} + return h.setCursorPosition(position, window) +} + +func (h *windowsAnsiEventHandler) HVP(row int, col int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("HVP: [[%d %d]]", row, col) + h.clearWrap() + return h.CUP(row, col) +} + +func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)}) + h.clearWrap() + return nil +} + +func (h *windowsAnsiEventHandler) DECOM(enable bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)}) + h.clearWrap() + h.originMode = enable + return h.CUP(1, 1) +} + +func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)}) + h.clearWrap() + if err := h.ED(2); err != nil { + return err + } + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + targetWidth := int16(80) + if use132 { + targetWidth = 132 + } + if info.Size.X < targetWidth { + if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { + h.logf("set buffer failed: %v", err) + return err + } + } + window := info.Window + window.Left = 0 + window.Right = targetWidth - 1 + if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { + h.logf("set window failed: %v", err) + return err + } + if info.Size.X > targetWidth { + if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { + h.logf("set buffer failed: %v", err) + return err + } + } + return SetConsoleCursorPosition(h.fd, COORD{0, 0}) +} + +func (h *windowsAnsiEventHandler) ED(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("ED: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + + // [J -- Erases from the cursor to the end of the screen, including the cursor position. + // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position. + // [2J -- Erases the complete display. The cursor does not move. + // Notes: + // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + var start COORD + var end COORD + + switch param { + case 0: + start = info.CursorPosition + end = COORD{info.Size.X - 1, info.Size.Y - 1} + + case 1: + start = COORD{0, 0} + end = info.CursorPosition + + case 2: + start = COORD{0, 0} + end = COORD{info.Size.X - 1, info.Size.Y - 1} + } + + err = h.clearRange(h.attributes, start, end) + if err != nil { + return err + } + + // If the whole buffer was cleared, move the window to the top while preserving + // the window-relative cursor position. + if param == 2 { + pos := info.CursorPosition + window := info.Window + pos.Y -= window.Top + window.Bottom -= window.Top + window.Top = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { + return err + } + } + + return nil +} + +func (h *windowsAnsiEventHandler) EL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("EL: [%v]", strconv.Itoa(param)) + h.clearWrap() + + // [K -- Erases from the cursor to the end of the line, including the cursor position. + // [1K -- Erases from the beginning of the line to the cursor, including the cursor position. + // [2K -- Erases the complete line. + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + var start COORD + var end COORD + + switch param { + case 0: + start = info.CursorPosition + end = COORD{info.Size.X, info.CursorPosition.Y} + + case 1: + start = COORD{0, info.CursorPosition.Y} + end = info.CursorPosition + + case 2: + start = COORD{0, info.CursorPosition.Y} + end = COORD{info.Size.X, info.CursorPosition.Y} + } + + err = h.clearRange(h.attributes, start, end) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) IL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("IL: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.insertLines(param) +} + +func (h *windowsAnsiEventHandler) DL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DL: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.deleteLines(param) +} + +func (h *windowsAnsiEventHandler) ICH(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("ICH: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.insertCharacters(param) +} + +func (h *windowsAnsiEventHandler) DCH(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DCH: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.deleteCharacters(param) +} + +func (h *windowsAnsiEventHandler) SGR(params []int) error { + if err := h.Flush(); err != nil { + return err + } + strings := []string{} + for _, v := range params { + strings = append(strings, strconv.Itoa(v)) + } + + h.logf("SGR: [%v]", strings) + + if len(params) <= 0 { + h.attributes = h.infoReset.Attributes + h.inverted = false + } else { + for _, attr := range params { + + if attr == ansiterm.ANSI_SGR_RESET { + h.attributes = h.infoReset.Attributes + h.inverted = false + continue + } + + h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr)) + } + } + + attributes := h.attributes + if h.inverted { + attributes = invertAttributes(attributes) + } + err := SetConsoleTextAttribute(h.fd, attributes) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) SU(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("SU: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.scrollUp(param) +} + +func (h *windowsAnsiEventHandler) SD(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("SD: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.scrollDown(param) +} + +func (h *windowsAnsiEventHandler) DA(params []string) error { + h.logf("DA: [%v]", params) + // DA cannot be implemented because it must send data on the VT100 input stream, + // which is not available to go-ansiterm. + return nil +} + +func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECSTBM: [%d, %d]", top, bottom) + + // Windows is 0 indexed, Linux is 1 indexed + h.sr.top = int16(top - 1) + h.sr.bottom = int16(bottom - 1) + + // This command also moves the cursor to the origin. + h.clearWrap() + return h.CUP(1, 1) +} + +func (h *windowsAnsiEventHandler) RI() error { + if err := h.Flush(); err != nil { + return err + } + h.logf("RI: []") + h.clearWrap() + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + sr := h.effectiveSr(info.Window) + if info.CursorPosition.Y == sr.top { + return h.scrollDown(1) + } + + return h.moveCursorVertical(-1) +} + +func (h *windowsAnsiEventHandler) IND() error { + h.logf("IND: []") + return h.executeLF() +} + +func (h *windowsAnsiEventHandler) Flush() error { + h.curInfo = nil + if h.buffer.Len() > 0 { + h.logf("Flush: [%s]", h.buffer.Bytes()) + if _, err := h.buffer.WriteTo(h.file); err != nil { + return err + } + } + + if h.wrapNext && !h.drewMarginByte { + h.logf("Flush: drawing margin byte '%c'", h.marginByte) + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}} + size := COORD{1, 1} + position := COORD{0, 0} + region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y} + if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil { + return err + } + h.drewMarginByte = true + } + return nil +} + +// cacheConsoleInfo ensures that the current console screen information has been queried +// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos. +func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { + if h.curInfo == nil { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return COORD{}, nil, err + } + h.curInfo = info + h.curPos = info.CursorPosition + } + return h.curPos, h.curInfo, nil +} + +func (h *windowsAnsiEventHandler) updatePos(pos COORD) { + if h.curInfo == nil { + panic("failed to call getCurrentInfo before calling updatePos") + } + h.curPos = pos +} + +// clearWrap clears the state where the cursor is in the margin +// waiting for the next character before wrapping the line. This must +// be done before most operations that act on the cursor. +func (h *windowsAnsiEventHandler) clearWrap() { + h.wrapNext = false + h.drewMarginByte = false +} diff --git a/vendor/github.com/skycoin/dmsg/.gitignore b/vendor/github.com/skycoin/dmsg/.gitignore index 553a6e7917..cd9864fccf 100644 --- a/vendor/github.com/skycoin/dmsg/.gitignore +++ b/vendor/github.com/skycoin/dmsg/.gitignore @@ -19,3 +19,4 @@ bin/ /dmsgpty-ui /hello.txt +/integration/integration-pids.csv diff --git a/vendor/github.com/skycoin/dmsg/Makefile b/vendor/github.com/skycoin/dmsg/Makefile index 21d6c3f4d0..75440c6f1e 100644 --- a/vendor/github.com/skycoin/dmsg/Makefile +++ b/vendor/github.com/skycoin/dmsg/Makefile @@ -1,4 +1,8 @@ -SHELL := /bin/bash +ifeq ($(OS),Windows_NT) + SHELL := pwsh +else + SHELL := /bin/bash +endif .DEFAULT_GOAL := help .PHONY : check lint install-linters dep test build @@ -6,12 +10,21 @@ SHELL := /bin/bash VERSION := $(shell git describe --always) RFC_3339 := "+%Y-%m-%dT%H:%M:%SZ" -DATE := $(shell date -u $(RFC_3339)) COMMIT := $(shell git rev-list -1 HEAD) -BIN := ${PWD}/bin +ifeq ($(OS),Windows_NT) + BIN := .\bin + BIN_DIR?=.\bin + CMD_DIR := .\cmd + DATE := $(shell powershell -Command date -u ${RFC_3339}) +else + BIN := ${PWD}/bin + BIN_DIR?=./bin + CMD_DIR := ./cmd + DATE := $(shell date -u ${RFC_3339}) +endif + OPTS?=GO111MODULE=on -BIN_DIR?=./bin TEST_OPTS:=-tags no_ci -cover -timeout=5m @@ -67,7 +80,11 @@ install: ## Install `dmsg-discovery`, `dmsg-server`, `dmsgget`,`dmsgpty-cli`, `d ${OPTS} go install ${BUILD_OPTS} ./cmd/* build: ## Build binaries into ./bin - mkdir -p ${BIN}; go build ${BUILD_OPTS} -o ${BIN} ./cmd/* + mkdir -p ${BIN}; go build ${BUILD_OPTS} -o ${BIN} ${CMD_DIR}/* + +build-windows: + powershell -Command new-item ${BIN} -itemtype directory -force + powershell 'Get-ChildItem ${CMD_DIR} | % { go build ${BUILD_OPTS} -o ${BIN} $$_.FullName }' build-deploy: ## Build for deployment Docker images go build -tags netgo ${BUILD_OPTS_DEPLOY} -o /release/dmsg-discovery ./cmd/dmsg-discovery @@ -105,5 +122,11 @@ attach-pty: ## Attach local dmsgpty tmux session. stop-all: stop-pty stop-dmsg stop-db ## Stop all local tmux sessions. +integration-windows-start: + powershell -Command .\integration\integration.ps1 start + +integration-windows-stop: + powershell -Command .\integration\integration.ps1 stop + help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/vendor/github.com/skycoin/dmsg/client.go b/vendor/github.com/skycoin/dmsg/client.go index ade841f210..7bec26aaf6 100644 --- a/vendor/github.com/skycoin/dmsg/client.go +++ b/vendor/github.com/skycoin/dmsg/client.go @@ -106,7 +106,7 @@ func NewClient(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Conf c.EntityCommon.init(pk, sk, dc, log, conf.UpdateInterval) // Init callback: on set session. - c.EntityCommon.setSessionCallback = func(ctx context.Context, sessionCount int) error { + c.EntityCommon.setSessionCallback = func(ctx context.Context) error { if err := c.EntityCommon.updateClientEntry(ctx, c.done); err != nil { return err } @@ -118,8 +118,8 @@ func NewClient(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Conf } // Init callback: on delete session. - c.EntityCommon.delSessionCallback = func(ctx context.Context, sessionCount int) error { - err := c.EntityCommon.updateClientEntry(ctx, c.done) + c.EntityCommon.delSessionCallback = func(ctx context.Context) error { + err := c.EntityCommon.delClientEntry(ctx, c.done) return err } @@ -149,9 +149,6 @@ func (ce *Client) Serve(ctx context.Context) { } }(cancellabelCtx) - // Ensure we start updateClientEntryLoop once only. - updateEntryLoopOnce := new(sync.Once) - for { if isClosed(ce.done) { return @@ -197,9 +194,6 @@ func (ce *Client) Serve(ctx context.Context) { } time.Sleep(serveWait) } - - // Only start the update entry loop once we have at least one session established. - updateEntryLoopOnce.Do(func() { go ce.updateClientEntryLoop(cancellabelCtx, ce.done) }) } } } @@ -239,9 +233,9 @@ func (ce *Client) Close() error { Info("Session closed.") } ce.sessions = make(map[cipher.PubKey]*SessionCommon) - ce.log.Info("All sessions closed.") ce.sessionsMx.Unlock() + ce.delSession(context.Background(), ce.pk) ce.porter.CloseAll(ce.log) }) diff --git a/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go b/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go index 02d0490845..6fbaa75e56 100644 --- a/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go +++ b/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go @@ -32,7 +32,6 @@ const ( // ServiceFlags represents common flags which are shared across services. type ServiceFlags struct { MetricsAddr string - HTTPAddr string Syslog string SyslogNet string LogLevel string @@ -77,7 +76,6 @@ func (sf *ServiceFlags) Init(rootCmd *cobra.Command, defaultTag, defaultConf str // flags rootCmd.Flags().StringVarP(&sf.MetricsAddr, "metrics", "m", sf.MetricsAddr, "address to serve metrics API from") - rootCmd.Flags().StringVarP(&sf.HTTPAddr, "http", "p", ":8082", "address to serve http API for health endpoint") rootCmd.Flags().StringVar(&sf.Syslog, "syslog", sf.Syslog, "address in which to dial to syslog server") rootCmd.Flags().StringVar(&sf.SyslogNet, "syslog-net", sf.SyslogNet, "network in which to dial to syslog server") rootCmd.Flags().StringVar(&sf.LogLevel, "syslog-lvl", sf.LogLevel, "minimum log level to report") diff --git a/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go b/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go index 56291a4822..a8b119e08c 100644 --- a/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go +++ b/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go @@ -16,7 +16,7 @@ func SignalContext(ctx context.Context, log logrus.FieldLogger) (context.Context ctx, cancel := context.WithCancel(ctx) - ch := make(chan os.Signal) + ch := make(chan os.Signal, 1) listenSigs := listenSignals() signal.Notify(ch, listenSigs...) diff --git a/vendor/github.com/skycoin/dmsg/disc/client.go b/vendor/github.com/skycoin/dmsg/disc/client.go index ba1fa19abe..7aa27a8af3 100644 --- a/vendor/github.com/skycoin/dmsg/disc/client.go +++ b/vendor/github.com/skycoin/dmsg/disc/client.go @@ -25,6 +25,7 @@ type APIClient interface { Entry(context.Context, cipher.PubKey) (*Entry, error) PostEntry(context.Context, *Entry) error PutEntry(context.Context, cipher.SecKey, *Entry) error + DelEntry(context.Context, *Entry) error AvailableServers(context.Context) ([]*Entry, error) } @@ -107,8 +108,62 @@ func (c *httpClient) PostEntry(ctx context.Context, e *Entry) error { req.Header.Set("Content-Type", "application/json") // Since v0.3.0 visors send ?timeout=true, before v0.3.0 do not. + // Since v0.5.0 visors send do not send ?timeout=true anymore. + q := req.URL.Query() + req.URL.RawQuery = q.Encode() + + req = req.WithContext(ctx) + + resp, err := c.client.Do(req) + if resp != nil { + defer func() { + if err := resp.Body.Close(); err != nil { + log.WithError(err).Warn("Failed to close response body.") + } + }() + } + if err != nil { + log.WithError(err).Error("Failed to perform request.") + return err + } + + if resp.StatusCode != http.StatusOK { + var httpResponse HTTPMessage + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + err = json.Unmarshal(bodyBytes, &httpResponse) + if err != nil { + return err + } + log.WithField("resp_body", httpResponse.Message). + WithField("resp_status", resp.StatusCode). + Error() + return errFromString(httpResponse.Message) + } + return nil +} + +// DelEntry creates a new Entry. +func (c *httpClient) DelEntry(ctx context.Context, e *Entry) error { + endpoint := c.address + "/dmsg-discovery/entry" + log := log.WithField("endpoint", endpoint) + + marshaledEntry, err := json.Marshal(e) + if err != nil { + return err + } + + req, err := http.NewRequest(http.MethodDelete, endpoint, bytes.NewBuffer(marshaledEntry)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + q := req.URL.Query() - q.Add("timeout", "true") req.URL.RawQuery = q.Encode() req = req.WithContext(ctx) diff --git a/vendor/github.com/skycoin/dmsg/disc/http_message.go b/vendor/github.com/skycoin/dmsg/disc/http_message.go index 7336bf6973..30c7aa6ed1 100644 --- a/vendor/github.com/skycoin/dmsg/disc/http_message.go +++ b/vendor/github.com/skycoin/dmsg/disc/http_message.go @@ -9,6 +9,7 @@ import ( var ( MsgEntrySet = HTTPMessage{Code: http.StatusOK, Message: "wrote a new entry"} MsgEntryUpdated = HTTPMessage{Code: http.StatusOK, Message: "wrote new entry iteration"} + MsgEntryDeleted = HTTPMessage{Code: http.StatusOK, Message: "deleted entry"} ) // HTTPMessage represents a message to be returned as an http response diff --git a/vendor/github.com/skycoin/dmsg/disc/testing.go b/vendor/github.com/skycoin/dmsg/disc/testing.go index a697319edc..9fc87fe277 100644 --- a/vendor/github.com/skycoin/dmsg/disc/testing.go +++ b/vendor/github.com/skycoin/dmsg/disc/testing.go @@ -35,6 +35,12 @@ func (m *mockClient) entry(pk cipher.PubKey) (Entry, bool) { return e, ok } +func (m *mockClient) delEntry(pk cipher.PubKey) { + m.mx.Lock() + defer m.mx.Unlock() + delete(m.entries, pk) +} + func (m *mockClient) setEntry(entry Entry) { m.mx.Lock() defer m.mx.Unlock() @@ -87,6 +93,12 @@ func (m *mockClient) PostEntry(_ context.Context, entry *Entry) error { return nil } +// DelEntry returns the mock client static public key associated entry +func (m *mockClient) DelEntry(_ context.Context, entry *Entry) error { + m.delEntry(entry.Static) + return nil +} + // PutEntry updates a previously set entry func (m *mockClient) PutEntry(ctx context.Context, sk cipher.SecKey, e *Entry) error { e.Sequence++ diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go index c2d7e01756..ac71769a63 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go @@ -6,13 +6,9 @@ import ( "io" "net" "os" - "os/signal" - "syscall" - "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" - terminal "golang.org/x/term" "github.com/skycoin/dmsg/cipher" ) @@ -29,7 +25,7 @@ func DefaultCLI() CLI { return CLI{ Log: logging.MustGetLogger("dmsgpty-cli"), Net: DefaultCLINet, - Addr: DefaultCLIAddr, + Addr: DefaultCLIAddr(), } } @@ -95,7 +91,7 @@ func (cli *CLI) prepareConn() (net.Conn, error) { cli.Net = DefaultCLINet } if cli.Addr == "" { - cli.Addr = DefaultCLIAddr + cli.Addr = DefaultCLIAddr() } cli.Log. @@ -109,26 +105,6 @@ func (cli *CLI) prepareConn() (net.Conn, error) { return conn, nil } -// prepareStdin sets stdin to raw mode and provides a function to restore the original state. -func (cli *CLI) prepareStdin() (restore func(), err error) { - var oldState *terminal.State - if oldState, err = terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { - cli.Log. - WithError(err). - Warn("Failed to set stdin to raw mode.") - return - } - restore = func() { - // Attempt to restore state. - if err := terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { - cli.Log. - WithError(err). - Error("Failed to restore original stdin state.") - } - } - return -} - // servePty serves a pty connection via the dmsgpty-host. func (cli *CLI) servePty(ctx context.Context, ptyC *PtyClient, cmd string, args []string) error { ctx, cancel := context.WithCancel(ctx) @@ -167,28 +143,3 @@ func (cli *CLI) servePty(ctx context.Context, ptyC *PtyClient, cmd string, args return nil } - -// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. -func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { - ch := make(chan os.Signal, 1) - signal.Notify(ch, syscall.SIGWINCH) - for { - select { - case <-ctx.Done(): - return nil - case <-ch: - winSize, err := getPtySize(os.Stdin) - if err != nil { - return fmt.Errorf("failed to obtain window size: %v", err) - } - if err := ptyC.SetPtySize(winSize); err != nil { - return fmt.Errorf("failed to set remote window size: %v", err) - } - } - } -} - -// getPtySize obtains the size of the local terminal. -func getPtySize(t *os.File) (*pty.Winsize, error) { - return pty.GetsizeFull(t) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go new file mode 100644 index 0000000000..b5b3277d65 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go @@ -0,0 +1,63 @@ +//+build !windows + +package dmsgpty + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + + "github.com/creack/pty" + "golang.org/x/crypto/ssh/terminal" +) + +// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. +func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGWINCH) + for { + select { + case <-ctx.Done(): + return nil + case <-ch: + winSize, err := getPtySize(os.Stdin) + if err != nil { + return fmt.Errorf("failed to obtain window size: %v", err) + } + ws, err := NewWinSize(winSize) + if err != nil { + return fmt.Errorf("failed to convert pty size to WinSize: %v", err) + } + if err := ptyC.SetPtySize(ws); err != nil { + return fmt.Errorf("failed to set remote window size: %v", err) + } + } + } +} + +// getPtySize obtains the size of the local terminal. +func getPtySize(t *os.File) (*pty.Winsize, error) { + return pty.GetsizeFull(t) +} + +// prepareStdin sets stdin to raw mode and provides a function to restore the original state. +func (cli *CLI) prepareStdin() (restore func(), err error) { + var oldState *terminal.State + if oldState, err = terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { + cli.Log. + WithError(err). + Warn("Failed to set stdin to raw mode.") + return + } + restore = func() { + // Attempt to restore state. + if err = terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { + cli.Log. + WithError(err). + Error("Failed to restore original stdin state.") + } + } + return +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go new file mode 100644 index 0000000000..01938d0cca --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go @@ -0,0 +1,44 @@ +//+build windows + +package dmsgpty + +import ( + "context" + "sync" + "time" + + "github.com/ActiveState/termtest/conpty" +) + +// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. +func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { + t := time.NewTicker(1 * time.Second) + mu := sync.RWMutex{} + var initialSize *WinSize + for { + select { + case <-ctx.Done(): + t.Stop() + return nil + case <-t.C: + mu.Lock() + size, err := getSize() + if err == nil { + if initialSize == nil { + initialSize = size + } else if initialSize.X != size.X || initialSize.Y != size.Y { + initialSize = size + if err = ptyC.SetPtySize(initialSize); err != nil { + mu.Unlock() + return err + } + } + } + mu.Unlock() + } + } +} + +func (cli *CLI) prepareStdin() (restore func(), err error) { + return conpty.InitTerminal(true) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go b/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go index 84f2a7a2d5..03ded6f813 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go @@ -3,6 +3,9 @@ package dmsgpty import ( "fmt" "os" + "path/filepath" + "runtime" + "strings" "github.com/skycoin/dmsg" ) @@ -26,7 +29,7 @@ func DefaultConfig() Config { DmsgSessions: dmsg.DefaultMinSessions, DmsgPort: DefaultPort, CLINet: DefaultCLINet, - CLIAddr: DefaultCLIAddr, + CLIAddr: DefaultCLIAddr(), } } @@ -40,3 +43,50 @@ func WriteConfig(conf Config, path string) error { enc.SetIndent("", " ") return enc.Encode(&conf) } + +func findStringsEnclosedBy(str string, sep string, result []string, lastIndex int) ([]string, int) { + s := strings.Index(str, sep) + if s == -1 { + return result, lastIndex + } + newS := str[s+len(sep):] + e := strings.Index(newS, sep) + if e == -1 { + lastIndex += len(sep) + return result, lastIndex + } + res := newS[:e] + if res != "" { + result = append(result, res) + } + last := s + len(res) + len(sep) + if lastIndex == -1 { + lastIndex = last + } else { + lastIndex += last + } + str = str[last:] + return findStringsEnclosedBy(str, sep, result, lastIndex) +} + +// ParseWindowsEnv finds '%'-enclosed windows env in json string +func ParseWindowsEnv(cliAddr string) string { + if runtime.GOOS == "windows" { + var res []string + results, lastIndex := findStringsEnclosedBy(cliAddr, "%", res, -1) + if len(results) > 0 { + paths := make([]string, len(results)+1) + for i, s := range results { + pth := os.Getenv(strings.ToUpper(s)) + if pth != "" { + paths[i] = pth + } + } + paths[len(paths)-1] = strings.Replace(cliAddr[lastIndex:], string(filepath.Separator), "", 1) + cliAddr = filepath.Join(paths...) + _ = strings.ReplaceAll(cliAddr, `\`, `\\`) + return cliAddr + } + } + return cliAddr +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const.go index 74bec2933d..4497d75379 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/const.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const.go @@ -12,15 +12,3 @@ const ( WhitelistRPCName = "whitelist" WhitelistURI = "dmsgpty/whitelist" ) - -// Constants related to CLI. -const ( - DefaultCLINet = "unix" - DefaultCLIAddr = "/tmp/dmsgpty.sock" -) - -// Constants related to dmsg. -const ( - DefaultPort = uint16(22) - DefaultCmd = "/bin/bash" -) diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go new file mode 100644 index 0000000000..8616378c7e --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go @@ -0,0 +1,24 @@ +//+build !windows + +package dmsgpty + +import ( + "os" + "path/filepath" +) + +// Constants related to CLI. +const ( + DefaultCLINet = "unix" +) + +// Constants related to dmsg. +const ( + DefaultPort = uint16(22) + DefaultCmd = "/bin/bash" +) + +// DefaultCLIAddr gets the default cli address (temp address) +func DefaultCLIAddr() string { + return filepath.Join(os.TempDir(), "dmsgpty.sock") +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go new file mode 100644 index 0000000000..6b5ce832e7 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go @@ -0,0 +1,27 @@ +//+build windows + +package dmsgpty + +import ( + "os" + "path/filepath" +) + +const ( + DefaultCLINet = "unix" +) + +// Constants related to dmsg. +const ( + DefaultPort = uint16(22) + DefaultCmd = `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` +) + +// DefaultCLIAddr gets the default cli address +func DefaultCLIAddr() string { + homedir, err := os.UserHomeDir() + if err != nil { + homedir = os.TempDir() + } + return filepath.Join(homedir, "dmsgpty.sock") +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/host.go b/vendor/github.com/skycoin/dmsg/dmsgpty/host.go index 98b6bc00a7..51f1df01f9 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/host.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/host.go @@ -46,7 +46,7 @@ func (h *Host) ServeCLI(ctx context.Context, lis net.Listener) error { _ = lis.Close() //nolint:errcheck }() - log := logging.MustGetLogger("dmsgpty:cli-server") + log := logging.MustGetLogger("dmsg_pty:cli-server") mux := cliEndpoints(h) @@ -86,9 +86,11 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { return err } + log := logging.MustGetLogger("dmsg_pty") + go func() { <-ctx.Done() - h.log(). + log. WithError(lis.Close()). Info("Serve() ended.") }() @@ -96,7 +98,7 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { for { stream, err := lis.AcceptStream() if err != nil { - log := h.log().WithError(err) + log := log.WithError(err) if err, ok := err.(net.Error); ok && err.Temporary() { log.Warn("Failed to accept dmsg.Stream with temporary error, continuing...") continue @@ -111,7 +113,7 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { } rPK := stream.RawRemoteAddr().PK - log := h.log().WithField("remote_pk", rPK.String()) + log := log.WithField("remote_pk", rPK.String()) log.Info("Processing dmsg.Stream...") if !h.authorize(log, rPK) { diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go index af94e5d9df..92deb1abfa 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go @@ -4,10 +4,8 @@ import ( "fmt" "io" "net/rpc" - "os" "sync" - "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" @@ -72,21 +70,6 @@ func (sc *PtyClient) close() (closed bool) { return closed } -// Start starts the pty. -func (sc *PtyClient) Start(name string, arg ...string) error { - size, err := pty.GetsizeFull(os.Stdin) - if err != nil { - sc.log.WithError(err).Warn("failed to obtain terminal size") - size = nil - } - return sc.StartWithSize(name, arg, size) -} - -// StartWithSize starts the pty with a specified size. -func (sc *PtyClient) StartWithSize(name string, arg []string, size *pty.Winsize) error { - return sc.call("Start", &CommandReq{Name: name, Arg: arg, Size: size}, &empty) -} - // Stop stops the pty. func (sc *PtyClient) Stop() error { return sc.call("Stop", &empty, &empty) @@ -107,11 +90,6 @@ func (sc *PtyClient) Write(b []byte) (int, error) { return n, processRPCError(err) } -// SetPtySize sets the pty size. -func (sc *PtyClient) SetPtySize(size *pty.Winsize) error { - return sc.call("SetPtySize", size, &empty) -} - func (*PtyClient) rpcMethod(m string) string { return PtyRPCName + "." + m } @@ -125,3 +103,22 @@ func (sc *PtyClient) call(method string, args, reply interface{}) error { return call.Error } } + +// Start starts the pty. +func (sc *PtyClient) Start(name string, arg ...string) error { + return sc.call("Start", &CommandReq{ + Name: name, + Arg: arg, + Size: nil, + }, &empty) +} + +// StartWithSize starts the pty with a specified size. +func (sc *PtyClient) StartWithSize(name string, arg []string, c *WinSize) error { + return sc.call("Start", &CommandReq{Name: name, Arg: arg, Size: c}, &empty) +} + +// SetPtySize sets the pty size. +func (sc *PtyClient) SetPtySize(size *WinSize) error { + return sc.call("SetPtySize", size, &empty) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go new file mode 100644 index 0000000000..36965a440d --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go @@ -0,0 +1,31 @@ +//+build windows + +package dmsgpty + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +// getSize gets windows terminal size +func getSize() (*WinSize, error) { + var bufInfo windows.ConsoleScreenBufferInfo + c, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) + if err != nil { + return nil, err + } + if err = windows.GetConsoleScreenBufferInfo(c, &bufInfo); err != nil { + if errors.Is(err, windows.ERROR_INVALID_HANDLE) { + return &WinSize{ + X: 80, + Y: 30, + }, nil + } + return nil, err + } + return NewWinSize(&windows.Coord{ + X: bufInfo.Window.Right - bufInfo.Window.Left + 1, + Y: bufInfo.Window.Bottom - bufInfo.Window.Top + 1, + }) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go index abb0508ec5..cf6aab8801 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go @@ -1,8 +1,12 @@ package dmsgpty -import ( - "github.com/creack/pty" -) +// WinSize wraps around pty.Winsize and *windows.Coord +type WinSize struct { + X uint16 + Y uint16 + Rows uint16 + Cols uint16 +} // PtyGateway represents a pty gateway, hosted by the pty.SessionServer type PtyGateway interface { @@ -10,7 +14,14 @@ type PtyGateway interface { Stop(_, _ *struct{}) error Read(reqN *int, respB *[]byte) error Write(reqB *[]byte, respN *int) error - SetPtySize(size *pty.Winsize, _ *struct{}) error + SetPtySize(size *WinSize, _ *struct{}) error +} + +// CommandReq represents a pty command. +type CommandReq struct { + Name string + Arg []string + Size *WinSize } // LocalPtyGateway is the gateway to a local pty. @@ -23,18 +34,6 @@ func NewPtyGateway(ses *Pty) PtyGateway { return &LocalPtyGateway{ses: ses} } -// CommandReq represents a pty command. -type CommandReq struct { - Name string - Arg []string - Size *pty.Winsize -} - -// Start starts the local pty. -func (g *LocalPtyGateway) Start(req *CommandReq, _ *struct{}) error { - return g.ses.Start(req.Name, req.Arg, req.Size) -} - // Stop stops the local pty. func (g *LocalPtyGateway) Stop(_, _ *struct{}) error { return g.ses.Stop() @@ -48,6 +47,11 @@ func (g *LocalPtyGateway) Read(reqN *int, respB *[]byte) error { return err } +// Start starts the local pty. +func (g *LocalPtyGateway) Start(req *CommandReq, _ *struct{}) error { + return g.ses.Start(req.Name, req.Arg, req.Size) +} + // Write writes to the local pty. func (g *LocalPtyGateway) Write(wb *[]byte, n *int) error { var err error @@ -56,10 +60,15 @@ func (g *LocalPtyGateway) Write(wb *[]byte, n *int) error { } // SetPtySize sets the local pty's window size. -func (g *LocalPtyGateway) SetPtySize(size *pty.Winsize, _ *struct{}) error { +func (g *LocalPtyGateway) SetPtySize(size *WinSize, _ *struct{}) error { return g.ses.SetPtySize(size) } +// SetPtySize sets the remote pty's window size. +func (g *ProxiedPtyGateway) SetPtySize(size *WinSize, _ *struct{}) error { + return g.ptyC.SetPtySize(size) +} + // ProxiedPtyGateway is an RPC gateway for a remote pty. type ProxiedPtyGateway struct { ptyC *PtyClient @@ -94,8 +103,3 @@ func (g *ProxiedPtyGateway) Write(reqB *[]byte, respN *int) error { *respN, err = g.ptyC.Write(*reqB) return err } - -// SetPtySize sets the remote pty's window size. -func (g *ProxiedPtyGateway) SetPtySize(size *pty.Winsize, _ *struct{}) error { - return g.ptyC.SetPtySize(size) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go new file mode 100644 index 0000000000..4176d90448 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go @@ -0,0 +1,32 @@ +//+build !windows + +package dmsgpty + +import ( + "errors" + + "github.com/creack/pty" +) + +// NewWinSize creates a new WinSize wrapper object +func NewWinSize(w *pty.Winsize) (*WinSize, error) { + if w == nil { + return nil, errors.New("pty size cannot be nil") + } + return &WinSize{ + X: w.X, + Y: w.Y, + Rows: w.Rows, + Cols: w.Cols, + }, nil +} + +// PtySize returns *pty.Winsize +func (w *WinSize) PtySize() *pty.Winsize { + return &pty.Winsize{ + Rows: w.Rows, + Cols: w.Cols, + X: w.X, + Y: w.Y, + } +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go new file mode 100644 index 0000000000..199c01b3ee --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go @@ -0,0 +1,28 @@ +//+build windows + +package dmsgpty + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +// NewWinSize creates a new WinSize object +func NewWinSize(w *windows.Coord) (*WinSize, error) { + if w == nil { + return nil, errors.New("pty size is nil") + } + return &WinSize{ + X: uint16(w.X), + Y: uint16(w.Y), + }, nil +} + +// PtySize returns *windows.Coord object +func (w *WinSize) PtySize() *windows.Coord { + return &windows.Coord{ + X: int16(w.X), + Y: int16(w.Y), + } +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go similarity index 80% rename from vendor/github.com/skycoin/dmsg/dmsgpty/pty.go rename to vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go index 2122a00800..b7dc14d122 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go @@ -1,3 +1,5 @@ +//+build !windows + package dmsgpty import ( @@ -26,27 +28,6 @@ func NewPty() *Pty { return new(Pty) } -// Start runs a command with the given command name, args and optional window size. -func (s *Pty) Start(name string, args []string, size *pty.Winsize) error { - s.mx.Lock() - defer s.mx.Unlock() - - if s.pty != nil { - return ErrPtyAlreadyRunning - } - - cmd := exec.Command(name, args...) //nolint:gosec - cmd.Env = os.Environ() - - f, err := pty.StartWithSize(cmd, size) //nolint:gosec - if err != nil { - return err - } - - s.pty = f - return nil -} - // Stop stops the running command and closes the pty. func (s *Pty) Stop() error { s.mx.Lock() @@ -85,8 +66,37 @@ func (s *Pty) Write(b []byte) (int, error) { return s.pty.Write(b) } +// Start runs a command with the given command name, args and optional window size. +func (s *Pty) Start(name string, args []string, size *WinSize) error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty != nil { + return ErrPtyAlreadyRunning + } + + cmd := exec.Command(name, args...) //nolint:gosec + cmd.Env = os.Environ() + var sz *pty.Winsize + var err error + + if size == nil { + sz = nil + } else { + sz = size.PtySize() + } + + f, err := pty.StartWithSize(cmd, sz) //nolint:gosec + if err != nil { + return err + } + + s.pty = f + return nil +} + // SetPtySize sets the pty size. -func (s *Pty) SetPtySize(size *pty.Winsize) error { +func (s *Pty) SetPtySize(size *WinSize) error { s.mx.RLock() defer s.mx.RUnlock() @@ -94,5 +104,7 @@ func (s *Pty) SetPtySize(size *pty.Winsize) error { return ErrPtyNotRunning } - return pty.Setsize(s.pty, size) + sz := size.PtySize() + + return pty.Setsize(s.pty, sz) } diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go new file mode 100644 index 0000000000..f19f5bb4f2 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go @@ -0,0 +1,125 @@ +//+build windows + +package dmsgpty + +import ( + "errors" + "fmt" + "os" + "sync" + "syscall" + + "github.com/ActiveState/termtest/conpty" +) + +// Pty errors. +var ( + ErrPtyAlreadyRunning = errors.New("a pty session is already running") + ErrPtyNotRunning = errors.New("no active pty session") +) + +// Pty runs a local pty. +type Pty struct { + pty *conpty.ConPty + mx sync.RWMutex +} + +// NewPty creates a new Pty. +func NewPty() *Pty { + return new(Pty) +} + +// Stop stops the running command and closes the pty. +func (s *Pty) Stop() error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty == nil { + return ErrPtyNotRunning + } + + err := s.pty.Close() + s.pty = nil + return err +} + +// Read reads any stdout or stderr outputs from the pty. +func (s *Pty) Read(b []byte) (int, error) { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.pty == nil { + return 0, ErrPtyNotRunning + } + + return s.pty.OutPipe().Read(b) +} + +// Write writes to the stdin of the pty. +func (s *Pty) Write(b []byte) (int, error) { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.pty == nil { + return 0, ErrPtyNotRunning + } + + res, err := s.pty.Write(b) + return int(res), err +} + +// Start runs a command with the given command name, args and optional window size. +func (s *Pty) Start(name string, args []string, size *WinSize) error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty != nil { + return ErrPtyAlreadyRunning + } + + var err error + + if size == nil { + size, err = getSize() + if err != nil { + return err + } + + } + fmt.Printf("Size of term: X=>%d, Y=>%d\n", size.X, size.Y) + pty, err := conpty.New( + int16(size.X), int16(size.Y), + ) + if err != nil { + return err + } + + pid, _, err := pty.Spawn( + name, + args, + &syscall.ProcAttr{ + Env: os.Environ(), + }, + ) + + if err != nil { + return err + } + + fmt.Printf("starting process with pid %d \n", pid) + + s.pty = pty + return nil +} + +// SetPtySize sets the pty size. +func (s *Pty) SetPtySize(size *WinSize) error { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.pty == nil { + return ErrPtyNotRunning + } + + return s.pty.Resize(uint16(size.X), uint16(size.Y)) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go index bf1b5d4a15..b75d52c434 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go @@ -10,7 +10,6 @@ import ( "sync/atomic" "time" - "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" "nhooyr.io/websocket" @@ -32,7 +31,7 @@ type UIConfig struct { // DefaultUIConfig returns the default UI config. func DefaultUIConfig() UIConfig { return UIConfig{ - CmdName: "/bin/bash", + CmdName: DefaultCmd, CmdArgs: nil, } } @@ -155,7 +154,7 @@ func (ui *UI) Handler() http.HandlerFunc { } defer func() { log.WithError(ptyC.Close()).Debug("Closed ptyC.") }() - if err := ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, &pty.Winsize{Rows: wsRows, Cols: wsCols}); err != nil { + if err = ui.uiStartSize(ptyC); err != nil { log.Print("xxxx") writeWSError(log, wsConn, err) diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go new file mode 100644 index 0000000000..4047d058b1 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go @@ -0,0 +1,15 @@ +//+build !windows + +package dmsgpty + +import ( + "github.com/creack/pty" +) + +func (ui *UI) uiStartSize(ptyC *PtyClient) error { + winSize, err := NewWinSize(&pty.Winsize{Rows: wsRows, Cols: wsCols}) + if err != nil { + return err + } + return ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, winSize) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go new file mode 100644 index 0000000000..b8905dc5e6 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go @@ -0,0 +1,16 @@ +//+build windows + +package dmsgpty + +import "golang.org/x/sys/windows" + +func (ui *UI) uiStartSize(ptyC *PtyClient) error { + ws, err := NewWinSize(&windows.Coord{ + X: wsCols, + Y: wsRows, + }) + if err != nil { + return err + } + return ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, ws) +} diff --git a/vendor/github.com/skycoin/dmsg/entity_common.go b/vendor/github.com/skycoin/dmsg/entity_common.go index a790b04e6e..afcd01764e 100644 --- a/vendor/github.com/skycoin/dmsg/entity_common.go +++ b/vendor/github.com/skycoin/dmsg/entity_common.go @@ -30,8 +30,8 @@ type EntityCommon struct { log logrus.FieldLogger - setSessionCallback func(ctx context.Context, sessionCount int) error - delSessionCallback func(ctx context.Context, sessionCount int) error + setSessionCallback func(ctx context.Context) error + delSessionCallback func(ctx context.Context) error } func (c *EntityCommon) init(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, log logrus.FieldLogger, updateInterval time.Duration) { @@ -107,7 +107,7 @@ func (c *EntityCommon) setSession(ctx context.Context, dSes *SessionCommon) bool c.sessions[dSes.RemotePK()] = dSes if c.setSessionCallback != nil { - if err := c.setSessionCallback(ctx, len(c.sessions)); err != nil { + if err := c.setSessionCallback(ctx); err != nil { c.log. WithField("func", "EntityCommon.setSession"). WithError(err). @@ -121,7 +121,7 @@ func (c *EntityCommon) delSession(ctx context.Context, pk cipher.PubKey) { c.sessionsMx.Lock() delete(c.sessions, pk) if c.delSessionCallback != nil { - if err := c.delSessionCallback(ctx, len(c.sessions)); err != nil { + if err := c.delSessionCallback(ctx); err != nil { c.log. WithField("func", "EntityCommon.delSession"). WithError(err). @@ -250,33 +250,21 @@ func (c *EntityCommon) updateClientEntry(ctx context.Context, done chan struct{} return c.dc.PutEntry(ctx, c.sk, entry) } -func (c *EntityCommon) updateClientEntryLoop(ctx context.Context, done chan struct{}) { - t := time.NewTimer(c.updateInterval) - defer t.Stop() - - for { - select { - case <-ctx.Done(): - return +func (c *EntityCommon) delClientEntry(ctx context.Context, _ chan struct{}) (err error) { - case <-t.C: - if lastUpdate, due := c.updateIsDue(); !due { - t.Reset(c.updateInterval - time.Since(lastUpdate)) - continue - } - - c.sessionsMx.Lock() - err := c.updateClientEntry(ctx, done) - c.sessionsMx.Unlock() - - if err != nil { - c.log.WithError(err).Warn("Failed to update discovery entry.") - } + entry, err := c.dc.Entry(ctx, c.pk) + if err != nil { + return err + } - // Ensure we trigger another update within given 'updateInterval'. - t.Reset(c.updateInterval) + defer func() { + if err == nil { + c.log.Debug("Entry Deleted successfully.") } - } + }() + + c.log.WithField("entry", entry).Debug("Deleting entry.") + return c.dc.DelEntry(ctx, entry) } func getServerEntry(ctx context.Context, dc disc.APIClient, srvPK cipher.PubKey) (*disc.Entry, error) { diff --git a/vendor/github.com/skycoin/dmsg/go.mod b/vendor/github.com/skycoin/dmsg/go.mod index 8c834f956c..d762bd66bb 100644 --- a/vendor/github.com/skycoin/dmsg/go.mod +++ b/vendor/github.com/skycoin/dmsg/go.mod @@ -3,6 +3,7 @@ module github.com/skycoin/dmsg go 1.16 require ( + github.com/ActiveState/termtest/conpty v0.5.0 github.com/VictoriaMetrics/metrics v1.12.3 github.com/creack/pty v1.1.10 github.com/go-chi/chi v4.1.2+incompatible @@ -24,9 +25,9 @@ require ( github.com/skycoin/yamux v0.0.0-20200803175205-571ceb89da9f github.com/spf13/cobra v0.0.5 github.com/stretchr/testify v1.4.0 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb - golang.org/x/sys v0.0.0-20210112080510-489259a85091 - golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect nhooyr.io/websocket v1.8.2 ) diff --git a/vendor/github.com/skycoin/dmsg/go.sum b/vendor/github.com/skycoin/dmsg/go.sum index ac9db4222f..a9c78bcebf 100644 --- a/vendor/github.com/skycoin/dmsg/go.sum +++ b/vendor/github.com/skycoin/dmsg/go.sum @@ -1,7 +1,13 @@ +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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I= github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -84,6 +90,8 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pires/go-proxyproto v0.3.3 h1:jOXGrsAfSQVFiD1hWg1aiHpLYsd6SJw/8cLN594sB7Q= github.com/pires/go-proxyproto v0.3.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -143,10 +151,13 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0= golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/skycoin/dmsg/server.go b/vendor/github.com/skycoin/dmsg/server.go index 7ecc88f84f..638d9d118e 100644 --- a/vendor/github.com/skycoin/dmsg/server.go +++ b/vendor/github.com/skycoin/dmsg/server.go @@ -67,10 +67,10 @@ func NewServer(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Serv s.done = make(chan struct{}) s.addrDone = make(chan struct{}) s.maxSessions = conf.MaxSessions - s.setSessionCallback = func(ctx context.Context, sessionCount int) error { + s.setSessionCallback = func(ctx context.Context) error { return s.updateServerEntry(ctx, s.AdvertisedAddr(), s.maxSessions) } - s.delSessionCallback = func(ctx context.Context, sessionCount int) error { + s.delSessionCallback = func(ctx context.Context) error { return s.updateServerEntry(ctx, s.AdvertisedAddr(), s.maxSessions) } return s diff --git a/vendor/modules.txt b/vendor/modules.txt index 3a033f2e10..134651e835 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,6 +1,11 @@ +# github.com/ActiveState/termtest/conpty v0.5.0 +github.com/ActiveState/termtest/conpty # github.com/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51 ## explicit github.com/AudriusButkevicius/pfilter +# github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 +github.com/Azure/go-ansiterm +github.com/Azure/go-ansiterm/winterm # github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d ## explicit github.com/StackExchange/wmi @@ -128,7 +133,7 @@ github.com/shirou/gopsutil/process ## explicit github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/syslog -# github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 +# github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 => ../dmsg ## explicit github.com/skycoin/dmsg github.com/skycoin/dmsg/buildinfo @@ -288,3 +293,4 @@ nhooyr.io/websocket/internal/bpool nhooyr.io/websocket/internal/errd nhooyr.io/websocket/internal/wsjs nhooyr.io/websocket/internal/xsync +# github.com/skycoin/dmsg => ../dmsg From 0a2d71ebb50b8d577ba47183f0eb6c2a5fd5bd87 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 17:40:14 +0530 Subject: [PATCH 03/13] Revert "Test dep" This reverts commit 4508a1179ca901d4b60f9d758ddf21c704285482. --- go.mod | 2 +- go.sum | 9 +- .../ActiveState/termtest/conpty/LICENSE | 29 - .../ActiveState/termtest/conpty/README.md | 23 - .../termtest/conpty/conpty_windows.go | 250 ------ .../ActiveState/termtest/conpty/doc.go | 11 - .../termtest/conpty/exec_windows.go | 161 ---- .../ActiveState/termtest/conpty/go.mod | 8 - .../ActiveState/termtest/conpty/go.sum | 4 - .../termtest/conpty/syscall_windows.go | 112 --- .../ActiveState/termtest/conpty/term_other.go | 7 - .../termtest/conpty/term_windows.go | 61 -- vendor/github.com/Azure/go-ansiterm/LICENSE | 21 - vendor/github.com/Azure/go-ansiterm/README.md | 12 - .../github.com/Azure/go-ansiterm/constants.go | 188 ----- .../github.com/Azure/go-ansiterm/context.go | 7 - .../Azure/go-ansiterm/csi_entry_state.go | 49 -- .../Azure/go-ansiterm/csi_param_state.go | 38 - .../go-ansiterm/escape_intermediate_state.go | 36 - .../Azure/go-ansiterm/escape_state.go | 47 -- .../Azure/go-ansiterm/event_handler.go | 90 --- .../Azure/go-ansiterm/ground_state.go | 24 - .../Azure/go-ansiterm/osc_string_state.go | 31 - vendor/github.com/Azure/go-ansiterm/parser.go | 151 ---- .../go-ansiterm/parser_action_helpers.go | 99 --- .../Azure/go-ansiterm/parser_actions.go | 119 --- vendor/github.com/Azure/go-ansiterm/states.go | 71 -- .../github.com/Azure/go-ansiterm/utilities.go | 21 - .../Azure/go-ansiterm/winterm/ansi.go | 182 ----- .../Azure/go-ansiterm/winterm/api.go | 327 -------- .../go-ansiterm/winterm/attr_translation.go | 100 --- .../go-ansiterm/winterm/cursor_helpers.go | 101 --- .../go-ansiterm/winterm/erase_helpers.go | 84 -- .../go-ansiterm/winterm/scroll_helper.go | 118 --- .../Azure/go-ansiterm/winterm/utilities.go | 9 - .../go-ansiterm/winterm/win_event_handler.go | 743 ------------------ vendor/github.com/skycoin/dmsg/.gitignore | 1 - vendor/github.com/skycoin/dmsg/Makefile | 33 +- vendor/github.com/skycoin/dmsg/client.go | 14 +- .../skycoin/dmsg/cmdutil/service_flags.go | 2 + .../skycoin/dmsg/cmdutil/signal_context.go | 2 +- vendor/github.com/skycoin/dmsg/disc/client.go | 57 +- .../skycoin/dmsg/disc/http_message.go | 1 - .../github.com/skycoin/dmsg/disc/testing.go | 12 - vendor/github.com/skycoin/dmsg/dmsgpty/cli.go | 53 +- .../skycoin/dmsg/dmsgpty/cli_unix.go | 63 -- .../skycoin/dmsg/dmsgpty/cli_windows.go | 44 -- .../github.com/skycoin/dmsg/dmsgpty/conf.go | 52 +- .../github.com/skycoin/dmsg/dmsgpty/const.go | 12 + .../skycoin/dmsg/dmsgpty/const_unix.go | 24 - .../skycoin/dmsg/dmsgpty/const_windows.go | 27 - .../github.com/skycoin/dmsg/dmsgpty/host.go | 10 +- .../dmsg/dmsgpty/{pty_unix.go => pty.go} | 58 +- .../skycoin/dmsg/dmsgpty/pty_client.go | 41 +- .../dmsg/dmsgpty/pty_client_windows.go | 31 - .../skycoin/dmsg/dmsgpty/pty_gateway.go | 48 +- .../skycoin/dmsg/dmsgpty/pty_gateway_unix.go | 32 - .../dmsg/dmsgpty/pty_gateway_windows.go | 28 - .../skycoin/dmsg/dmsgpty/pty_windows.go | 125 --- vendor/github.com/skycoin/dmsg/dmsgpty/ui.go | 5 +- .../skycoin/dmsg/dmsgpty/ui_unix.go | 15 - .../skycoin/dmsg/dmsgpty/ui_windows.go | 16 - .../github.com/skycoin/dmsg/entity_common.go | 44 +- vendor/github.com/skycoin/dmsg/go.mod | 5 +- vendor/github.com/skycoin/dmsg/go.sum | 11 - vendor/github.com/skycoin/dmsg/server.go | 4 +- vendor/modules.txt | 8 +- 67 files changed, 194 insertions(+), 4029 deletions(-) delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/LICENSE delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/README.md delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/doc.go delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/exec_windows.go delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/go.mod delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/go.sum delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/term_other.go delete mode 100644 vendor/github.com/ActiveState/termtest/conpty/term_windows.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/LICENSE delete mode 100644 vendor/github.com/Azure/go-ansiterm/README.md delete mode 100644 vendor/github.com/Azure/go-ansiterm/constants.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/context.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/csi_entry_state.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/csi_param_state.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/escape_state.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/event_handler.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/ground_state.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/osc_string_state.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/parser.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/parser_actions.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/states.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/utilities.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/ansi.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/api.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/utilities.go delete mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go rename vendor/github.com/skycoin/dmsg/dmsgpty/{pty_unix.go => pty.go} (80%) delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go delete mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go diff --git a/go.mod b/go.mod index e27c75dff3..f2953ba5bb 100644 --- a/go.mod +++ b/go.mod @@ -48,4 +48,4 @@ require ( ) // Uncomment for tests with alternate branches of 'dmsg' -replace github.com/skycoin/dmsg => ../dmsg +//replace github.com/skycoin/dmsg => ../dmsg diff --git a/go.sum b/go.sum index c405f682fe..ab807602ba 100644 --- a/go.sum +++ b/go.sum @@ -7,12 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -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/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51 h1:77WF6PJZQiA3OMt8Nl+PH/dbkszumosxunW36ZQj2QQ= github.com/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51/go.mod h1:EEEtt5r8y0gGHlRFF2+cLx0WUy/rKHnjALmom5E0+74= -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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= @@ -283,6 +279,8 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 h1:Dlf/sDocfSgjP+ipVxzOtDVkkLN1u6ZqUyXzp22AkU4= +github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2/go.mod h1:XguFKwECpSMq+/AKv8TCTsRlCEHSEIbqoaxOyceK2Ys= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6 h1:1Nc5EBY6pjfw1kwW0duwyG+7WliWz5u9kgk1h5MnLuA= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:UXghlricA7J3aRD/k7p/zBObQfmBawwCxIVPVjz2Q3o= github.com/skycoin/skycoin v0.26.0/go.mod h1:78nHjQzd8KG0jJJVL/j0xMmrihXi70ti63fh8vXScJw= @@ -436,18 +434,17 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/ActiveState/termtest/conpty/LICENSE b/vendor/github.com/ActiveState/termtest/conpty/LICENSE deleted file mode 100644 index 0ea09c8e0d..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2020, ActiveState Software -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/ActiveState/termtest/conpty/README.md b/vendor/github.com/ActiveState/termtest/conpty/README.md deleted file mode 100644 index fb093f8559..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# termtest/conpty - -Support for the [Windows pseudo -console](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/) -in Go. - -Developed as part of the cross-platform terminal automation library -[expect](https://github.com/ActiveState/termtest/expect) for the [ActiveState -state tool](https://www.activestate.com/products/platform/state-tool/). - -## Example - -See ./cmd/example/main.go - -## Client configuration - -On Windows, you may have to adjust the programme that you are running in the -pseudo-console, by configuring the standard output handler to process virtual -terminal codes. See https://docs.microsoft.com/en-us/windows/console/setconsolemode - -This package comes with a convenience function `InitTerminal()` that you can -use in your client to set this option. - diff --git a/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go b/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go deleted file mode 100644 index e0a1821fc9..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2020 ActiveState Software. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file - -package conpty - -import ( - "fmt" - "log" - "os" - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -// ConPty represents a windows pseudo console. -// Attach a process to it by calling the Spawn() method. -// You can send UTF encoded commands to it with Write() and listen to -// its output stream by accessing the output pipe via OutPipe() -type ConPty struct { - hpCon *windows.Handle - pipeFdIn windows.Handle - pipeFdOut windows.Handle - startupInfo startupInfoEx - consoleSize uintptr - inPipe *os.File - outPipe *os.File - attributeListBuffer []byte -} - -// New returns a new ConPty pseudo terminal device -func New(columns int16, rows int16) (c *ConPty, err error) { - c = &ConPty{ - hpCon: new(windows.Handle), - startupInfo: startupInfoEx{}, - consoleSize: uintptr(columns) + (uintptr(rows) << 16), - } - err = c.createPseudoConsoleAndPipes() - if err != nil { - return nil, err - } - err = c.initializeStartupInfoAttachedToPTY() - if err != nil { - return nil, err - } - return -} - -// Close closes the pseudo-terminal and cleans up all attached resources -func (c *ConPty) Close() (err error) { - err = deleteProcThreadAttributeList(c.startupInfo.lpAttributeList) - if err != nil { - log.Printf("Failed to free delete proc thread attribute list: %v", err) - } - /* - _, err = windows.LocalFree(c.startupInfo.lpAttributeList) - if err != nil { - log.Printf("Failed to free the lpAttributeList") - } - */ - err = closePseudoConsole(*c.hpCon) - if err != nil { - log.Printf("Failed to close pseudo console: %v", err) - } - c.inPipe.Close() - c.outPipe.Close() - return -} - -// OutPipe returns the output pipe of the pseudo terminal -func (c *ConPty) OutPipe() *os.File { - return c.outPipe -} - -// InPipe returns input pipe of the pseudo terminal -// Note: It is safer to use the Write method to prevent partially-written VT sequences -// from corrupting the terminal -func (c *ConPty) InPipe() *os.File { - return c.inPipe -} - -func (c *ConPty) OutFd() uintptr { - return c.outPipe.Fd() -} - -// Write safely writes bytes to the pseudo terminal -func (c *ConPty) Write(buf []byte) (uint32, error) { - var n uint32 - err := windows.WriteFile(c.pipeFdIn, buf, &n, nil) - return n, err -} - -var zeroProcAttr syscall.ProcAttr - -// Spawn spawns a new process attached to the pseudo terminal -func (c *ConPty) Spawn(argv0 string, argv []string, attr *syscall.ProcAttr) (pid int, handle uintptr, err error) { - - if attr == nil { - attr = &zeroProcAttr - } - - if attr.Sys != nil { - log.Printf("Warning: SysProc attributes are not supported by Spawn.") - } - - if len(attr.Files) != 0 { - log.Printf("Warning: Ignoring 'Files' attribute in ProcAttr argument.") - } - - if len(attr.Dir) != 0 { - // StartProcess assumes that argv0 is relative to attr.Dir, - // because it implies Chdir(attr.Dir) before executing argv0. - // Windows CreateProcess assumes the opposite: it looks for - // argv0 relative to the current directory, and, only once the new - // process is started, it does Chdir(attr.Dir). We are adjusting - // for that difference here by making argv0 absolute. - var err error - argv0, err = joinExeDirAndFName(attr.Dir, argv0) - if err != nil { - return 0, 0, err - } - } - argv0p, err := windows.UTF16PtrFromString(argv0) - if err != nil { - return 0, 0, err - } - - // Windows CreateProcess takes the command line as a single string: - // use attr.CmdLine if set, else build the command line by escaping - // and joining each argument with spaces - cmdline := makeCmdLine(argv) - - var argvp *uint16 - if len(cmdline) != 0 { - argvp, err = windows.UTF16PtrFromString(cmdline) - if err != nil { - return 0, 0, err - } - } - - var dirp *uint16 - if len(attr.Dir) != 0 { - dirp, err = windows.UTF16PtrFromString(attr.Dir) - if err != nil { - return 0, 0, err - } - } - - c.startupInfo.startupInfo.Flags = windows.STARTF_USESTDHANDLES - - pi := new(windows.ProcessInformation) - - flags := uint32(windows.CREATE_UNICODE_ENVIRONMENT) | extendedStartupinfoPresent - - var zeroSec windows.SecurityAttributes - pSec := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(zeroSec)), InheritHandle: 1} - tSec := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(zeroSec)), InheritHandle: 1} - - // c.startupInfo.startupInfo.Cb = uint32(unsafe.Sizeof(c.startupInfo)) - err = windows.CreateProcess( - argv0p, - argvp, - pSec, // process handle not inheritable - tSec, // thread handles not inheritable, - false, - flags, - createEnvBlock(addCriticalEnv(dedupEnvCase(true, attr.Env))), - dirp, // use current directory later: dirp, - &c.startupInfo.startupInfo, - pi) - - if err != nil { - return 0, 0, err - } - defer windows.CloseHandle(windows.Handle(pi.Thread)) - - return int(pi.ProcessId), uintptr(pi.Process), nil -} - -func (c *ConPty) createPseudoConsoleAndPipes() (err error) { - var hPipePTYIn windows.Handle - var hPipePTYOut windows.Handle - - if err := windows.CreatePipe(&hPipePTYIn, &c.pipeFdIn, nil, 0); err != nil { - log.Fatalf("Failed to create PTY input pipe: %v", err) - } - if err := windows.CreatePipe(&c.pipeFdOut, &hPipePTYOut, nil, 0); err != nil { - log.Fatalf("Failed to create PTY output pipe: %v", err) - } - - err = createPseudoConsole(c.consoleSize, hPipePTYIn, hPipePTYOut, c.hpCon) - if err != nil { - return fmt.Errorf("failed to create pseudo console: %d, %v", uintptr(*c.hpCon), err) - } - - // Note: We can close the handles to the PTY-end of the pipes here - // because the handles are dup'ed into the ConHost and will be released - // when the ConPTY is destroyed. - if hPipePTYOut != windows.InvalidHandle { - windows.CloseHandle(hPipePTYOut) - } - if hPipePTYIn != windows.InvalidHandle { - windows.CloseHandle(hPipePTYIn) - } - - c.inPipe = os.NewFile(uintptr(c.pipeFdIn), "|0") - c.outPipe = os.NewFile(uintptr(c.pipeFdOut), "|1") - - return -} - -func (c *ConPty) Resize(cols uint16, rows uint16) error { - return resizePseudoConsole(*c.hpCon, uintptr(cols)+(uintptr(rows)<<16)) -} - -func (c *ConPty) initializeStartupInfoAttachedToPTY() (err error) { - - var attrListSize uint64 - c.startupInfo.startupInfo.Cb = uint32(unsafe.Sizeof(c.startupInfo)) - - err = initializeProcThreadAttributeList(0, 1, &attrListSize) - if err != nil { - return fmt.Errorf("could not retrieve list size: %v", err) - } - - c.attributeListBuffer = make([]byte, attrListSize) - // c.startupInfo.lpAttributeList, err = localAlloc(attrListSize) - // if err != nil { - // return fmt.Errorf("Could not allocate local memory: %v", err) - // } - - c.startupInfo.lpAttributeList = windows.Handle(unsafe.Pointer(&c.attributeListBuffer[0])) - - err = initializeProcThreadAttributeList(uintptr(c.startupInfo.lpAttributeList), 1, &attrListSize) - if err != nil { - return fmt.Errorf("failed to initialize proc thread attributes for conpty: %v", err) - } - - err = updateProcThreadAttributeList( - c.startupInfo.lpAttributeList, - procThreadAttributePseudoconsole, - *c.hpCon, - unsafe.Sizeof(*c.hpCon)) - if err != nil { - return fmt.Errorf("failed to update proc thread attributes attributes for conpty usage: %v", err) - } - - return -} diff --git a/vendor/github.com/ActiveState/termtest/conpty/doc.go b/vendor/github.com/ActiveState/termtest/conpty/doc.go deleted file mode 100644 index b423fb62cc..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2020 ActiveState Software. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file - -// Package conpty provides functions for creating a process attached to a -// ConPTY pseudo-terminal. This allows the process to call console specific -// API functions without an actual terminal being present. -// -// The concept is best explained in this blog post: -// https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ -package conpty diff --git a/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go b/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go deleted file mode 100644 index 6d0777054d..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. - -// This file has copies of unexported functions form the go source code, -// hence the above copyright message - -package conpty - -import ( - "os" - "strings" - "syscall" - "unicode/utf16" - - "golang.org/x/sys/windows" -) - -// makeCmdLine builds a command line out of args by escaping "special" -// characters and joining the arguments with spaces. -func makeCmdLine(args []string) string { - var s string - for _, v := range args { - if s != "" { - s += " " - } - s += windows.EscapeArg(v) - } - return s -} - -func isSlash(c uint8) bool { - return c == '\\' || c == '/' -} - -func normalizeDir(dir string) (name string, err error) { - ndir, err := syscall.FullPath(dir) - if err != nil { - return "", err - } - if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) { - // dir cannot have \\server\share\path form - return "", syscall.EINVAL - } - return ndir, nil -} - -func volToUpper(ch int) int { - if 'a' <= ch && ch <= 'z' { - ch += 'A' - 'a' - } - return ch -} - -func joinExeDirAndFName(dir, p string) (name string, err error) { - if len(p) == 0 { - return "", syscall.EINVAL - } - if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) { - // \\server\share\path form - return p, nil - } - if len(p) > 1 && p[1] == ':' { - // has drive letter - if len(p) == 2 { - return "", syscall.EINVAL - } - if isSlash(p[2]) { - return p, nil - } else { - d, err := normalizeDir(dir) - if err != nil { - return "", err - } - if volToUpper(int(p[0])) == volToUpper(int(d[0])) { - return syscall.FullPath(d + "\\" + p[2:]) - } else { - return syscall.FullPath(p) - } - } - } else { - // no drive letter - d, err := normalizeDir(dir) - if err != nil { - return "", err - } - if isSlash(p[0]) { - return windows.FullPath(d[:2] + p) - } else { - return windows.FullPath(d + "\\" + p) - } - } -} - -// createEnvBlock converts an array of environment strings into -// the representation required by CreateProcess: a sequence of NUL -// terminated strings followed by a nil. -// Last bytes are two UCS-2 NULs, or four NUL bytes. -func createEnvBlock(envv []string) *uint16 { - if len(envv) == 0 { - return &utf16.Encode([]rune("\x00\x00"))[0] - } - length := 0 - for _, s := range envv { - length += len(s) + 1 - } - length += 1 - - b := make([]byte, length) - i := 0 - for _, s := range envv { - l := len(s) - copy(b[i:i+l], []byte(s)) - copy(b[i+l:i+l+1], []byte{0}) - i = i + l + 1 - } - copy(b[i:i+1], []byte{0}) - - return &utf16.Encode([]rune(string(b)))[0] -} - -// dedupEnvCase is dedupEnv with a case option for testing. -// If caseInsensitive is true, the case of keys is ignored. -func dedupEnvCase(caseInsensitive bool, env []string) []string { - out := make([]string, 0, len(env)) - saw := make(map[string]int, len(env)) // key => index into out - for _, kv := range env { - eq := strings.Index(kv, "=") - if eq < 0 { - out = append(out, kv) - continue - } - k := kv[:eq] - if caseInsensitive { - k = strings.ToLower(k) - } - if dupIdx, isDup := saw[k]; isDup { - out[dupIdx] = kv - continue - } - saw[k] = len(out) - out = append(out, kv) - } - return out -} - -// addCriticalEnv adds any critical environment variables that are required -// (or at least almost always required) on the operating system. -// Currently this is only used for Windows. -func addCriticalEnv(env []string) []string { - for _, kv := range env { - eq := strings.Index(kv, "=") - if eq < 0 { - continue - } - k := kv[:eq] - if strings.EqualFold(k, "SYSTEMROOT") { - // We already have it. - return env - } - } - return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) -} diff --git a/vendor/github.com/ActiveState/termtest/conpty/go.mod b/vendor/github.com/ActiveState/termtest/conpty/go.mod deleted file mode 100644 index 67bb0a5f81..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/ActiveState/termtest/conpty - -go 1.12 - -require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 - golang.org/x/sys v0.0.0-20200428200454-593003d681fa -) diff --git a/vendor/github.com/ActiveState/termtest/conpty/go.sum b/vendor/github.com/ActiveState/termtest/conpty/go.sum deleted file mode 100644 index c1c7bf67bf..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -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= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go b/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go deleted file mode 100644 index 375043114f..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2020 ActiveState Software. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file - -package conpty - -import ( - "unsafe" - - "golang.org/x/sys/windows" -) - -// load some windows system procedures - -var ( - kernel32 = windows.NewLazySystemDLL("kernel32.dll") - procResizePseudoConsole = kernel32.NewProc("ResizePseudoConsole") - procCreatePseudoConsole = kernel32.NewProc("CreatePseudoConsole") - procClosePseudoConsole = kernel32.NewProc("ClosePseudoConsole") - procInitializeProcThreadAttributeList = kernel32.NewProc("InitializeProcThreadAttributeList") - procUpdateProcThreadAttribute = kernel32.NewProc("UpdateProcThreadAttribute") - procLocalAlloc = kernel32.NewProc("LocalAlloc") - procDeleteProcThreadAttributeList = kernel32.NewProc("DeleteProcThreadAttributeList") - procCreateProcessW = kernel32.NewProc("CreateProcessW") -) - -// an extended version of a process startup info, the attribute list points -// to a pseudo terminal object -type startupInfoEx struct { - startupInfo windows.StartupInfo - lpAttributeList windows.Handle -} - -// constant used in CreateProcessW indicating that extended startup info is present -const extendedStartupinfoPresent uint32 = 0x00080000 - -type procThreadAttribute uintptr - -// windows constant needed during initialization of extended startupinfo -const procThreadAttributePseudoconsole procThreadAttribute = 22 | 0x00020000 // this is the only one we support right now - -func initializeProcThreadAttributeList(attributeList uintptr, attributeCount uint32, listSize *uint64) (err error) { - - if attributeList == 0 { - procInitializeProcThreadAttributeList.Call(0, uintptr(attributeCount), 0, uintptr(unsafe.Pointer(listSize))) - return - } - r1, _, e1 := procInitializeProcThreadAttributeList.Call(attributeList, uintptr(attributeCount), 0, uintptr(unsafe.Pointer(listSize))) - - if r1 == 0 { // boolean FALSE - err = e1 - } - - return -} - -func updateProcThreadAttributeList(attributeList windows.Handle, attribute procThreadAttribute, lpValue windows.Handle, lpSize uintptr) (err error) { - - r1, _, e1 := procUpdateProcThreadAttribute.Call(uintptr(attributeList), 0, uintptr(attribute), uintptr(lpValue), lpSize, 0, 0) - - if r1 == 0 { // boolean FALSE - err = e1 - } - - return -} -func deleteProcThreadAttributeList(handle windows.Handle) (err error) { - r1, _, e1 := procDeleteProcThreadAttributeList.Call(uintptr(handle)) - - if r1 == 0 { // boolean FALSE - err = e1 - } - - return -} - -func localAlloc(size uint64) (ptr windows.Handle, err error) { - r1, _, e1 := procLocalAlloc.Call(uintptr(0x0040), uintptr(size)) - if r1 == 0 { - err = e1 - ptr = windows.InvalidHandle - return - } - ptr = windows.Handle(r1) - return -} - -func createPseudoConsole(consoleSize uintptr, ptyIn windows.Handle, ptyOut windows.Handle, hpCon *windows.Handle) (err error) { - r1, _, e1 := procCreatePseudoConsole.Call(consoleSize, uintptr(ptyIn), uintptr(ptyOut), 0, uintptr(unsafe.Pointer(hpCon))) - - if r1 != 0 { // !S_OK - err = e1 - } - return -} - -func resizePseudoConsole(handle windows.Handle, consoleSize uintptr) (err error) { - r1, _, e1 := procResizePseudoConsole.Call(uintptr(handle), consoleSize) - if r1 != 0 { // !S_OK - err = e1 - } - return -} - -func closePseudoConsole(handle windows.Handle) (err error) { - r1, _, e1 := procClosePseudoConsole.Call(uintptr(handle)) - if r1 == 0 { - err = e1 - } - - return -} diff --git a/vendor/github.com/ActiveState/termtest/conpty/term_other.go b/vendor/github.com/ActiveState/termtest/conpty/term_other.go deleted file mode 100644 index daef1c0792..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/term_other.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !windows - -package conpty - -func InitTerminal(_ bool) (func(), error) { - return func() {}, nil -} diff --git a/vendor/github.com/ActiveState/termtest/conpty/term_windows.go b/vendor/github.com/ActiveState/termtest/conpty/term_windows.go deleted file mode 100644 index df091b5bb6..0000000000 --- a/vendor/github.com/ActiveState/termtest/conpty/term_windows.go +++ /dev/null @@ -1,61 +0,0 @@ -// +build windows - -package conpty - -import ( - "fmt" - "log" - "syscall" - - "github.com/Azure/go-ansiterm/winterm" -) - -func InitTerminal(disableNewlineAutoReturn bool) (func(), error) { - stdoutFd := int(syscall.Stdout) - - // fmt.Printf("file descriptors <%d >%d\n", stdinFd, stdoutFd) - - oldOutMode, err := winterm.GetConsoleMode(uintptr(stdoutFd)) - if err != nil { - return func() {}, fmt.Errorf("failed to retrieve stdout mode: %w", err) - } - - // fmt.Printf("old modes: <%d >%d\n", oldInMode, oldOutMode) - newOutMode := oldOutMode | winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING - if disableNewlineAutoReturn { - newOutMode |= winterm.DISABLE_NEWLINE_AUTO_RETURN - } - - err = winterm.SetConsoleMode(uintptr(stdoutFd), newOutMode) - if err != nil { - return func() {}, fmt.Errorf("failed to set stdout mode: %w", err) - } - - // dump(uintptr(stdoutFd)) - return func() { - err = winterm.SetConsoleMode(uintptr(stdoutFd), oldOutMode) - if err != nil { - log.Fatalf("Failed to reset output terminal mode to %d: %v\n", oldOutMode, err) - } - }, nil -} - -func dump(fd uintptr) { - fmt.Printf("FD=%d\n", fd) - modes, err := winterm.GetConsoleMode(fd) - if err != nil { - panic(err) - } - - fmt.Printf("ENABLE_ECHO_INPUT=%d, ENABLE_PROCESSED_INPUT=%d ENABLE_LINE_INPUT=%d\n", - modes&winterm.ENABLE_ECHO_INPUT, - modes&winterm.ENABLE_PROCESSED_INPUT, - modes&winterm.ENABLE_LINE_INPUT) - fmt.Printf("ENABLE_WINDOW_INPUT=%d, ENABLE_MOUSE_INPUT=%d\n", - modes&winterm.ENABLE_WINDOW_INPUT, - modes&winterm.ENABLE_MOUSE_INPUT) - fmt.Printf("enableVirtualTerminalInput=%d, enableVirtualTerminalProcessing=%d, disableNewlineAutoReturn=%d\n", - modes&winterm.ENABLE_VIRTUAL_TERMINAL_INPUT, - modes&winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING, - modes&winterm.DISABLE_NEWLINE_AUTO_RETURN) -} diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE deleted file mode 100644 index e3d9a64d1d..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md deleted file mode 100644 index 261c041e7a..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# go-ansiterm - -This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent. - -For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position. - -The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). - -See parser_test.go for examples exercising the state machine and generating appropriate function calls. - ------ -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go deleted file mode 100644 index 96504a33bc..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/constants.go +++ /dev/null @@ -1,188 +0,0 @@ -package ansiterm - -const LogEnv = "DEBUG_TERMINAL" - -// ANSI constants -// References: -// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm -// -- http://man7.org/linux/man-pages/man4/console_codes.4.html -// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html -// -- http://en.wikipedia.org/wiki/ANSI_escape_code -// -- http://vt100.net/emu/dec_ansi_parser -// -- http://vt100.net/emu/vt500_parser.svg -// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html -// -- http://www.inwap.com/pdp10/ansicode.txt -const ( - // ECMA-48 Set Graphics Rendition - // Note: - // -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved - // -- Fonts could possibly be supported via SetCurrentConsoleFontEx - // -- Windows does not expose the per-window cursor (i.e., caret) blink times - ANSI_SGR_RESET = 0 - ANSI_SGR_BOLD = 1 - ANSI_SGR_DIM = 2 - _ANSI_SGR_ITALIC = 3 - ANSI_SGR_UNDERLINE = 4 - _ANSI_SGR_BLINKSLOW = 5 - _ANSI_SGR_BLINKFAST = 6 - ANSI_SGR_REVERSE = 7 - _ANSI_SGR_INVISIBLE = 8 - _ANSI_SGR_LINETHROUGH = 9 - _ANSI_SGR_FONT_00 = 10 - _ANSI_SGR_FONT_01 = 11 - _ANSI_SGR_FONT_02 = 12 - _ANSI_SGR_FONT_03 = 13 - _ANSI_SGR_FONT_04 = 14 - _ANSI_SGR_FONT_05 = 15 - _ANSI_SGR_FONT_06 = 16 - _ANSI_SGR_FONT_07 = 17 - _ANSI_SGR_FONT_08 = 18 - _ANSI_SGR_FONT_09 = 19 - _ANSI_SGR_FONT_10 = 20 - _ANSI_SGR_DOUBLEUNDERLINE = 21 - ANSI_SGR_BOLD_DIM_OFF = 22 - _ANSI_SGR_ITALIC_OFF = 23 - ANSI_SGR_UNDERLINE_OFF = 24 - _ANSI_SGR_BLINK_OFF = 25 - _ANSI_SGR_RESERVED_00 = 26 - ANSI_SGR_REVERSE_OFF = 27 - _ANSI_SGR_INVISIBLE_OFF = 28 - _ANSI_SGR_LINETHROUGH_OFF = 29 - ANSI_SGR_FOREGROUND_BLACK = 30 - ANSI_SGR_FOREGROUND_RED = 31 - ANSI_SGR_FOREGROUND_GREEN = 32 - ANSI_SGR_FOREGROUND_YELLOW = 33 - ANSI_SGR_FOREGROUND_BLUE = 34 - ANSI_SGR_FOREGROUND_MAGENTA = 35 - ANSI_SGR_FOREGROUND_CYAN = 36 - ANSI_SGR_FOREGROUND_WHITE = 37 - _ANSI_SGR_RESERVED_01 = 38 - ANSI_SGR_FOREGROUND_DEFAULT = 39 - ANSI_SGR_BACKGROUND_BLACK = 40 - ANSI_SGR_BACKGROUND_RED = 41 - ANSI_SGR_BACKGROUND_GREEN = 42 - ANSI_SGR_BACKGROUND_YELLOW = 43 - ANSI_SGR_BACKGROUND_BLUE = 44 - ANSI_SGR_BACKGROUND_MAGENTA = 45 - ANSI_SGR_BACKGROUND_CYAN = 46 - ANSI_SGR_BACKGROUND_WHITE = 47 - _ANSI_SGR_RESERVED_02 = 48 - ANSI_SGR_BACKGROUND_DEFAULT = 49 - // 50 - 65: Unsupported - - ANSI_MAX_CMD_LENGTH = 4096 - - MAX_INPUT_EVENTS = 128 - DEFAULT_WIDTH = 80 - DEFAULT_HEIGHT = 24 - - ANSI_BEL = 0x07 - ANSI_BACKSPACE = 0x08 - ANSI_TAB = 0x09 - ANSI_LINE_FEED = 0x0A - ANSI_VERTICAL_TAB = 0x0B - ANSI_FORM_FEED = 0x0C - ANSI_CARRIAGE_RETURN = 0x0D - ANSI_ESCAPE_PRIMARY = 0x1B - ANSI_ESCAPE_SECONDARY = 0x5B - ANSI_OSC_STRING_ENTRY = 0x5D - ANSI_COMMAND_FIRST = 0x40 - ANSI_COMMAND_LAST = 0x7E - DCS_ENTRY = 0x90 - CSI_ENTRY = 0x9B - OSC_STRING = 0x9D - ANSI_PARAMETER_SEP = ";" - ANSI_CMD_G0 = '(' - ANSI_CMD_G1 = ')' - ANSI_CMD_G2 = '*' - ANSI_CMD_G3 = '+' - ANSI_CMD_DECPNM = '>' - ANSI_CMD_DECPAM = '=' - ANSI_CMD_OSC = ']' - ANSI_CMD_STR_TERM = '\\' - - KEY_CONTROL_PARAM_2 = ";2" - KEY_CONTROL_PARAM_3 = ";3" - KEY_CONTROL_PARAM_4 = ";4" - KEY_CONTROL_PARAM_5 = ";5" - KEY_CONTROL_PARAM_6 = ";6" - KEY_CONTROL_PARAM_7 = ";7" - KEY_CONTROL_PARAM_8 = ";8" - KEY_ESC_CSI = "\x1B[" - KEY_ESC_N = "\x1BN" - KEY_ESC_O = "\x1BO" - - FILL_CHARACTER = ' ' -) - -func getByteRange(start byte, end byte) []byte { - bytes := make([]byte, 0, 32) - for i := start; i <= end; i++ { - bytes = append(bytes, byte(i)) - } - - return bytes -} - -var toGroundBytes = getToGroundBytes() -var executors = getExecuteBytes() - -// SPACE 20+A0 hex Always and everywhere a blank space -// Intermediate 20-2F hex !"#$%&'()*+,-./ -var intermeds = getByteRange(0x20, 0x2F) - -// Parameters 30-3F hex 0123456789:;<=>? -// CSI Parameters 30-39, 3B hex 0123456789; -var csiParams = getByteRange(0x30, 0x3F) - -var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) - -// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ -var upperCase = getByteRange(0x40, 0x5F) - -// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~ -var lowerCase = getByteRange(0x60, 0x7E) - -// Alphabetics 40-7E hex (all of upper and lower case) -var alphabetics = append(upperCase, lowerCase...) - -var printables = getByteRange(0x20, 0x7F) - -var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) -var escapeToGroundBytes = getEscapeToGroundBytes() - -// See http://www.vt100.net/emu/vt500_parser.png for description of the complex -// byte ranges below - -func getEscapeToGroundBytes() []byte { - escapeToGroundBytes := getByteRange(0x30, 0x4F) - escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...) - escapeToGroundBytes = append(escapeToGroundBytes, 0x59) - escapeToGroundBytes = append(escapeToGroundBytes, 0x5A) - escapeToGroundBytes = append(escapeToGroundBytes, 0x5C) - escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...) - return escapeToGroundBytes -} - -func getExecuteBytes() []byte { - executeBytes := getByteRange(0x00, 0x17) - executeBytes = append(executeBytes, 0x19) - executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...) - return executeBytes -} - -func getToGroundBytes() []byte { - groundBytes := []byte{0x18} - groundBytes = append(groundBytes, 0x1A) - groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...) - groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...) - groundBytes = append(groundBytes, 0x99) - groundBytes = append(groundBytes, 0x9A) - groundBytes = append(groundBytes, 0x9C) - return groundBytes -} - -// Delete 7F hex Always and everywhere ignored -// C1 Control 80-9F hex 32 additional control characters -// G1 Displayable A1-FE hex 94 additional displayable characters -// Special A0+FF hex Same as SPACE and DELETE diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go deleted file mode 100644 index 8d66e777c0..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/context.go +++ /dev/null @@ -1,7 +0,0 @@ -package ansiterm - -type ansiContext struct { - currentChar byte - paramBuffer []byte - interBuffer []byte -} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go deleted file mode 100644 index bcbe00d0c5..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go +++ /dev/null @@ -1,49 +0,0 @@ -package ansiterm - -type csiEntryState struct { - baseState -} - -func (csiState csiEntryState) Handle(b byte) (s state, e error) { - csiState.parser.logf("CsiEntry::Handle %#x", b) - - nextState, err := csiState.baseState.Handle(b) - if nextState != nil || err != nil { - return nextState, err - } - - switch { - case sliceContains(alphabetics, b): - return csiState.parser.ground, nil - case sliceContains(csiCollectables, b): - return csiState.parser.csiParam, nil - case sliceContains(executors, b): - return csiState, csiState.parser.execute() - } - - return csiState, nil -} - -func (csiState csiEntryState) Transition(s state) error { - csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.baseState.Transition(s) - - switch s { - case csiState.parser.ground: - return csiState.parser.csiDispatch() - case csiState.parser.csiParam: - switch { - case sliceContains(csiParams, csiState.parser.context.currentChar): - csiState.parser.collectParam() - case sliceContains(intermeds, csiState.parser.context.currentChar): - csiState.parser.collectInter() - } - } - - return nil -} - -func (csiState csiEntryState) Enter() error { - csiState.parser.clear() - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go deleted file mode 100644 index 7ed5e01c34..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go +++ /dev/null @@ -1,38 +0,0 @@ -package ansiterm - -type csiParamState struct { - baseState -} - -func (csiState csiParamState) Handle(b byte) (s state, e error) { - csiState.parser.logf("CsiParam::Handle %#x", b) - - nextState, err := csiState.baseState.Handle(b) - if nextState != nil || err != nil { - return nextState, err - } - - switch { - case sliceContains(alphabetics, b): - return csiState.parser.ground, nil - case sliceContains(csiCollectables, b): - csiState.parser.collectParam() - return csiState, nil - case sliceContains(executors, b): - return csiState, csiState.parser.execute() - } - - return csiState, nil -} - -func (csiState csiParamState) Transition(s state) error { - csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) - csiState.baseState.Transition(s) - - switch s { - case csiState.parser.ground: - return csiState.parser.csiDispatch() - } - - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go deleted file mode 100644 index 1c719db9e4..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go +++ /dev/null @@ -1,36 +0,0 @@ -package ansiterm - -type escapeIntermediateState struct { - baseState -} - -func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { - escState.parser.logf("escapeIntermediateState::Handle %#x", b) - nextState, err := escState.baseState.Handle(b) - if nextState != nil || err != nil { - return nextState, err - } - - switch { - case sliceContains(intermeds, b): - return escState, escState.parser.collectInter() - case sliceContains(executors, b): - return escState, escState.parser.execute() - case sliceContains(escapeIntermediateToGroundBytes, b): - return escState.parser.ground, nil - } - - return escState, nil -} - -func (escState escapeIntermediateState) Transition(s state) error { - escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) - escState.baseState.Transition(s) - - switch s { - case escState.parser.ground: - return escState.parser.escDispatch() - } - - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go deleted file mode 100644 index 6390abd231..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/escape_state.go +++ /dev/null @@ -1,47 +0,0 @@ -package ansiterm - -type escapeState struct { - baseState -} - -func (escState escapeState) Handle(b byte) (s state, e error) { - escState.parser.logf("escapeState::Handle %#x", b) - nextState, err := escState.baseState.Handle(b) - if nextState != nil || err != nil { - return nextState, err - } - - switch { - case b == ANSI_ESCAPE_SECONDARY: - return escState.parser.csiEntry, nil - case b == ANSI_OSC_STRING_ENTRY: - return escState.parser.oscString, nil - case sliceContains(executors, b): - return escState, escState.parser.execute() - case sliceContains(escapeToGroundBytes, b): - return escState.parser.ground, nil - case sliceContains(intermeds, b): - return escState.parser.escapeIntermediate, nil - } - - return escState, nil -} - -func (escState escapeState) Transition(s state) error { - escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name()) - escState.baseState.Transition(s) - - switch s { - case escState.parser.ground: - return escState.parser.escDispatch() - case escState.parser.escapeIntermediate: - return escState.parser.collectInter() - } - - return nil -} - -func (escState escapeState) Enter() error { - escState.parser.clear() - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go deleted file mode 100644 index 98087b38c2..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/event_handler.go +++ /dev/null @@ -1,90 +0,0 @@ -package ansiterm - -type AnsiEventHandler interface { - // Print - Print(b byte) error - - // Execute C0 commands - Execute(b byte) error - - // CUrsor Up - CUU(int) error - - // CUrsor Down - CUD(int) error - - // CUrsor Forward - CUF(int) error - - // CUrsor Backward - CUB(int) error - - // Cursor to Next Line - CNL(int) error - - // Cursor to Previous Line - CPL(int) error - - // Cursor Horizontal position Absolute - CHA(int) error - - // Vertical line Position Absolute - VPA(int) error - - // CUrsor Position - CUP(int, int) error - - // Horizontal and Vertical Position (depends on PUM) - HVP(int, int) error - - // Text Cursor Enable Mode - DECTCEM(bool) error - - // Origin Mode - DECOM(bool) error - - // 132 Column Mode - DECCOLM(bool) error - - // Erase in Display - ED(int) error - - // Erase in Line - EL(int) error - - // Insert Line - IL(int) error - - // Delete Line - DL(int) error - - // Insert Character - ICH(int) error - - // Delete Character - DCH(int) error - - // Set Graphics Rendition - SGR([]int) error - - // Pan Down - SU(int) error - - // Pan Up - SD(int) error - - // Device Attributes - DA([]string) error - - // Set Top and Bottom Margins - DECSTBM(int, int) error - - // Index - IND() error - - // Reverse Index - RI() error - - // Flush updates from previous commands - Flush() error -} diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go deleted file mode 100644 index 52451e9469..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/ground_state.go +++ /dev/null @@ -1,24 +0,0 @@ -package ansiterm - -type groundState struct { - baseState -} - -func (gs groundState) Handle(b byte) (s state, e error) { - gs.parser.context.currentChar = b - - nextState, err := gs.baseState.Handle(b) - if nextState != nil || err != nil { - return nextState, err - } - - switch { - case sliceContains(printables, b): - return gs, gs.parser.print() - - case sliceContains(executors, b): - return gs, gs.parser.execute() - } - - return gs, nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go deleted file mode 100644 index 593b10ab69..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go +++ /dev/null @@ -1,31 +0,0 @@ -package ansiterm - -type oscStringState struct { - baseState -} - -func (oscState oscStringState) Handle(b byte) (s state, e error) { - oscState.parser.logf("OscString::Handle %#x", b) - nextState, err := oscState.baseState.Handle(b) - if nextState != nil || err != nil { - return nextState, err - } - - switch { - case isOscStringTerminator(b): - return oscState.parser.ground, nil - } - - return oscState, nil -} - -// See below for OSC string terminators for linux -// http://man7.org/linux/man-pages/man4/console_codes.4.html -func isOscStringTerminator(b byte) bool { - - if b == ANSI_BEL || b == 0x5C { - return true - } - - return false -} diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go deleted file mode 100644 index 03cec7ada6..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/parser.go +++ /dev/null @@ -1,151 +0,0 @@ -package ansiterm - -import ( - "errors" - "log" - "os" -) - -type AnsiParser struct { - currState state - eventHandler AnsiEventHandler - context *ansiContext - csiEntry state - csiParam state - dcsEntry state - escape state - escapeIntermediate state - error state - ground state - oscString state - stateMap []state - - logf func(string, ...interface{}) -} - -type Option func(*AnsiParser) - -func WithLogf(f func(string, ...interface{})) Option { - return func(ap *AnsiParser) { - ap.logf = f - } -} - -func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser { - ap := &AnsiParser{ - eventHandler: evtHandler, - context: &ansiContext{}, - } - for _, o := range opts { - o(ap) - } - - if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" { - logFile, _ := os.Create("ansiParser.log") - logger := log.New(logFile, "", log.LstdFlags) - if ap.logf != nil { - l := ap.logf - ap.logf = func(s string, v ...interface{}) { - l(s, v...) - logger.Printf(s, v...) - } - } else { - ap.logf = logger.Printf - } - } - - if ap.logf == nil { - ap.logf = func(string, ...interface{}) {} - } - - ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}} - ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}} - ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}} - ap.escape = escapeState{baseState{name: "Escape", parser: ap}} - ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}} - ap.error = errorState{baseState{name: "Error", parser: ap}} - ap.ground = groundState{baseState{name: "Ground", parser: ap}} - ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}} - - ap.stateMap = []state{ - ap.csiEntry, - ap.csiParam, - ap.dcsEntry, - ap.escape, - ap.escapeIntermediate, - ap.error, - ap.ground, - ap.oscString, - } - - ap.currState = getState(initialState, ap.stateMap) - - ap.logf("CreateParser: parser %p", ap) - return ap -} - -func getState(name string, states []state) state { - for _, el := range states { - if el.Name() == name { - return el - } - } - - return nil -} - -func (ap *AnsiParser) Parse(bytes []byte) (int, error) { - for i, b := range bytes { - if err := ap.handle(b); err != nil { - return i, err - } - } - - return len(bytes), ap.eventHandler.Flush() -} - -func (ap *AnsiParser) handle(b byte) error { - ap.context.currentChar = b - newState, err := ap.currState.Handle(b) - if err != nil { - return err - } - - if newState == nil { - ap.logf("WARNING: newState is nil") - return errors.New("New state of 'nil' is invalid.") - } - - if newState != ap.currState { - if err := ap.changeState(newState); err != nil { - return err - } - } - - return nil -} - -func (ap *AnsiParser) changeState(newState state) error { - ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name()) - - // Exit old state - if err := ap.currState.Exit(); err != nil { - ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err) - return err - } - - // Perform transition action - if err := ap.currState.Transition(newState); err != nil { - ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err) - return err - } - - // Enter new state - if err := newState.Enter(); err != nil { - ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err) - return err - } - - ap.currState = newState - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go deleted file mode 100644 index de0a1f9cde..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go +++ /dev/null @@ -1,99 +0,0 @@ -package ansiterm - -import ( - "strconv" -) - -func parseParams(bytes []byte) ([]string, error) { - paramBuff := make([]byte, 0, 0) - params := []string{} - - for _, v := range bytes { - if v == ';' { - if len(paramBuff) > 0 { - // Completed parameter, append it to the list - s := string(paramBuff) - params = append(params, s) - paramBuff = make([]byte, 0, 0) - } - } else { - paramBuff = append(paramBuff, v) - } - } - - // Last parameter may not be terminated with ';' - if len(paramBuff) > 0 { - s := string(paramBuff) - params = append(params, s) - } - - return params, nil -} - -func parseCmd(context ansiContext) (string, error) { - return string(context.currentChar), nil -} - -func getInt(params []string, dflt int) int { - i := getInts(params, 1, dflt)[0] - return i -} - -func getInts(params []string, minCount int, dflt int) []int { - ints := []int{} - - for _, v := range params { - i, _ := strconv.Atoi(v) - // Zero is mapped to the default value in VT100. - if i == 0 { - i = dflt - } - ints = append(ints, i) - } - - if len(ints) < minCount { - remaining := minCount - len(ints) - for i := 0; i < remaining; i++ { - ints = append(ints, dflt) - } - } - - return ints -} - -func (ap *AnsiParser) modeDispatch(param string, set bool) error { - switch param { - case "?3": - return ap.eventHandler.DECCOLM(set) - case "?6": - return ap.eventHandler.DECOM(set) - case "?25": - return ap.eventHandler.DECTCEM(set) - } - return nil -} - -func (ap *AnsiParser) hDispatch(params []string) error { - if len(params) == 1 { - return ap.modeDispatch(params[0], true) - } - - return nil -} - -func (ap *AnsiParser) lDispatch(params []string) error { - if len(params) == 1 { - return ap.modeDispatch(params[0], false) - } - - return nil -} - -func getEraseParam(params []string) int { - param := getInt(params, 0) - if param < 0 || 3 < param { - param = 0 - } - - return param -} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go deleted file mode 100644 index 0bb5e51e9a..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/parser_actions.go +++ /dev/null @@ -1,119 +0,0 @@ -package ansiterm - -func (ap *AnsiParser) collectParam() error { - currChar := ap.context.currentChar - ap.logf("collectParam %#x", currChar) - ap.context.paramBuffer = append(ap.context.paramBuffer, currChar) - return nil -} - -func (ap *AnsiParser) collectInter() error { - currChar := ap.context.currentChar - ap.logf("collectInter %#x", currChar) - ap.context.paramBuffer = append(ap.context.interBuffer, currChar) - return nil -} - -func (ap *AnsiParser) escDispatch() error { - cmd, _ := parseCmd(*ap.context) - intermeds := ap.context.interBuffer - ap.logf("escDispatch currentChar: %#x", ap.context.currentChar) - ap.logf("escDispatch: %v(%v)", cmd, intermeds) - - switch cmd { - case "D": // IND - return ap.eventHandler.IND() - case "E": // NEL, equivalent to CRLF - err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN) - if err == nil { - err = ap.eventHandler.Execute(ANSI_LINE_FEED) - } - return err - case "M": // RI - return ap.eventHandler.RI() - } - - return nil -} - -func (ap *AnsiParser) csiDispatch() error { - cmd, _ := parseCmd(*ap.context) - params, _ := parseParams(ap.context.paramBuffer) - ap.logf("Parsed params: %v with length: %d", params, len(params)) - - ap.logf("csiDispatch: %v(%v)", cmd, params) - - switch cmd { - case "@": - return ap.eventHandler.ICH(getInt(params, 1)) - case "A": - return ap.eventHandler.CUU(getInt(params, 1)) - case "B": - return ap.eventHandler.CUD(getInt(params, 1)) - case "C": - return ap.eventHandler.CUF(getInt(params, 1)) - case "D": - return ap.eventHandler.CUB(getInt(params, 1)) - case "E": - return ap.eventHandler.CNL(getInt(params, 1)) - case "F": - return ap.eventHandler.CPL(getInt(params, 1)) - case "G": - return ap.eventHandler.CHA(getInt(params, 1)) - case "H": - ints := getInts(params, 2, 1) - x, y := ints[0], ints[1] - return ap.eventHandler.CUP(x, y) - case "J": - param := getEraseParam(params) - return ap.eventHandler.ED(param) - case "K": - param := getEraseParam(params) - return ap.eventHandler.EL(param) - case "L": - return ap.eventHandler.IL(getInt(params, 1)) - case "M": - return ap.eventHandler.DL(getInt(params, 1)) - case "P": - return ap.eventHandler.DCH(getInt(params, 1)) - case "S": - return ap.eventHandler.SU(getInt(params, 1)) - case "T": - return ap.eventHandler.SD(getInt(params, 1)) - case "c": - return ap.eventHandler.DA(params) - case "d": - return ap.eventHandler.VPA(getInt(params, 1)) - case "f": - ints := getInts(params, 2, 1) - x, y := ints[0], ints[1] - return ap.eventHandler.HVP(x, y) - case "h": - return ap.hDispatch(params) - case "l": - return ap.lDispatch(params) - case "m": - return ap.eventHandler.SGR(getInts(params, 1, 0)) - case "r": - ints := getInts(params, 2, 1) - top, bottom := ints[0], ints[1] - return ap.eventHandler.DECSTBM(top, bottom) - default: - ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context) - return nil - } - -} - -func (ap *AnsiParser) print() error { - return ap.eventHandler.Print(ap.context.currentChar) -} - -func (ap *AnsiParser) clear() error { - ap.context = &ansiContext{} - return nil -} - -func (ap *AnsiParser) execute() error { - return ap.eventHandler.Execute(ap.context.currentChar) -} diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go deleted file mode 100644 index f2ea1fcd12..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/states.go +++ /dev/null @@ -1,71 +0,0 @@ -package ansiterm - -type stateID int - -type state interface { - Enter() error - Exit() error - Handle(byte) (state, error) - Name() string - Transition(state) error -} - -type baseState struct { - name string - parser *AnsiParser -} - -func (base baseState) Enter() error { - return nil -} - -func (base baseState) Exit() error { - return nil -} - -func (base baseState) Handle(b byte) (s state, e error) { - - switch { - case b == CSI_ENTRY: - return base.parser.csiEntry, nil - case b == DCS_ENTRY: - return base.parser.dcsEntry, nil - case b == ANSI_ESCAPE_PRIMARY: - return base.parser.escape, nil - case b == OSC_STRING: - return base.parser.oscString, nil - case sliceContains(toGroundBytes, b): - return base.parser.ground, nil - } - - return nil, nil -} - -func (base baseState) Name() string { - return base.name -} - -func (base baseState) Transition(s state) error { - if s == base.parser.ground { - execBytes := []byte{0x18} - execBytes = append(execBytes, 0x1A) - execBytes = append(execBytes, getByteRange(0x80, 0x8F)...) - execBytes = append(execBytes, getByteRange(0x91, 0x97)...) - execBytes = append(execBytes, 0x99) - execBytes = append(execBytes, 0x9A) - - if sliceContains(execBytes, base.parser.context.currentChar) { - return base.parser.execute() - } - } - - return nil -} - -type dcsEntryState struct { - baseState -} - -type errorState struct { - baseState -} diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go deleted file mode 100644 index 392114493a..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/utilities.go +++ /dev/null @@ -1,21 +0,0 @@ -package ansiterm - -import ( - "strconv" -) - -func sliceContains(bytes []byte, b byte) bool { - for _, v := range bytes { - if v == b { - return true - } - } - - return false -} - -func convertBytesToInteger(bytes []byte) int { - s := string(bytes) - i, _ := strconv.Atoi(s) - return i -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go deleted file mode 100644 index a673279726..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go +++ /dev/null @@ -1,182 +0,0 @@ -// +build windows - -package winterm - -import ( - "fmt" - "os" - "strconv" - "strings" - "syscall" - - "github.com/Azure/go-ansiterm" -) - -// Windows keyboard constants -// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx. -const ( - VK_PRIOR = 0x21 // PAGE UP key - VK_NEXT = 0x22 // PAGE DOWN key - VK_END = 0x23 // END key - VK_HOME = 0x24 // HOME key - VK_LEFT = 0x25 // LEFT ARROW key - VK_UP = 0x26 // UP ARROW key - VK_RIGHT = 0x27 // RIGHT ARROW key - VK_DOWN = 0x28 // DOWN ARROW key - VK_SELECT = 0x29 // SELECT key - VK_PRINT = 0x2A // PRINT key - VK_EXECUTE = 0x2B // EXECUTE key - VK_SNAPSHOT = 0x2C // PRINT SCREEN key - VK_INSERT = 0x2D // INS key - VK_DELETE = 0x2E // DEL key - VK_HELP = 0x2F // HELP key - VK_F1 = 0x70 // F1 key - VK_F2 = 0x71 // F2 key - VK_F3 = 0x72 // F3 key - VK_F4 = 0x73 // F4 key - VK_F5 = 0x74 // F5 key - VK_F6 = 0x75 // F6 key - VK_F7 = 0x76 // F7 key - VK_F8 = 0x77 // F8 key - VK_F9 = 0x78 // F9 key - VK_F10 = 0x79 // F10 key - VK_F11 = 0x7A // F11 key - VK_F12 = 0x7B // F12 key - - RIGHT_ALT_PRESSED = 0x0001 - LEFT_ALT_PRESSED = 0x0002 - RIGHT_CTRL_PRESSED = 0x0004 - LEFT_CTRL_PRESSED = 0x0008 - SHIFT_PRESSED = 0x0010 - NUMLOCK_ON = 0x0020 - SCROLLLOCK_ON = 0x0040 - CAPSLOCK_ON = 0x0080 - ENHANCED_KEY = 0x0100 -) - -type ansiCommand struct { - CommandBytes []byte - Command string - Parameters []string - IsSpecial bool -} - -func newAnsiCommand(command []byte) *ansiCommand { - - if isCharacterSelectionCmdChar(command[1]) { - // Is Character Set Selection commands - return &ansiCommand{ - CommandBytes: command, - Command: string(command), - IsSpecial: true, - } - } - - // last char is command character - lastCharIndex := len(command) - 1 - - ac := &ansiCommand{ - CommandBytes: command, - Command: string(command[lastCharIndex]), - IsSpecial: false, - } - - // more than a single escape - if lastCharIndex != 0 { - start := 1 - // skip if double char escape sequence - if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { - start++ - } - // convert this to GetNextParam method - ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) - } - - return ac -} - -func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { - if index < 0 || index >= len(ac.Parameters) { - return defaultValue - } - - param, err := strconv.ParseInt(ac.Parameters[index], 10, 16) - if err != nil { - return defaultValue - } - - return int16(param) -} - -func (ac *ansiCommand) String() string { - return fmt.Sprintf("0x%v \"%v\" (\"%v\")", - bytesToHex(ac.CommandBytes), - ac.Command, - strings.Join(ac.Parameters, "\",\"")) -} - -// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands. -// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. -func isAnsiCommandChar(b byte) bool { - switch { - case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: - return true - case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: - // non-CSI escape sequence terminator - return true - case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: - // String escape sequence terminator - return true - } - return false -} - -func isXtermOscSequence(command []byte, current byte) bool { - return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) -} - -func isCharacterSelectionCmdChar(b byte) bool { - return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) -} - -// bytesToHex converts a slice of bytes to a human-readable string. -func bytesToHex(b []byte) string { - hex := make([]string, len(b)) - for i, ch := range b { - hex[i] = fmt.Sprintf("%X", ch) - } - return strings.Join(hex, "") -} - -// ensureInRange adjusts the passed value, if necessary, to ensure it is within -// the passed min / max range. -func ensureInRange(n int16, min int16, max int16) int16 { - if n < min { - return min - } else if n > max { - return max - } else { - return n - } -} - -func GetStdFile(nFile int) (*os.File, uintptr) { - var file *os.File - switch nFile { - case syscall.STD_INPUT_HANDLE: - file = os.Stdin - case syscall.STD_OUTPUT_HANDLE: - file = os.Stdout - case syscall.STD_ERROR_HANDLE: - file = os.Stderr - default: - panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile)) - } - - fd, err := syscall.GetStdHandle(nFile) - if err != nil { - panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err)) - } - - return file, uintptr(fd) -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go deleted file mode 100644 index 6055e33b91..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/api.go +++ /dev/null @@ -1,327 +0,0 @@ -// +build windows - -package winterm - -import ( - "fmt" - "syscall" - "unsafe" -) - -//=========================================================================================================== -// IMPORTANT NOTE: -// -// The methods below make extensive use of the "unsafe" package to obtain the required pointers. -// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack -// variables) the pointers reference *before* the API completes. -// -// As a result, in those cases, the code must hint that the variables remain in active by invoking the -// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer -// require unsafe pointers. -// -// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform -// the garbage collector the variables remain in use if: -// -// -- The value is not a pointer (e.g., int32, struct) -// -- The value is not referenced by the method after passing the pointer to Windows -// -// See http://golang.org/doc/go1.3. -//=========================================================================================================== - -var ( - kernel32DLL = syscall.NewLazyDLL("kernel32.dll") - - getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo") - setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo") - setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition") - setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode") - getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") - setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize") - scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA") - setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") - setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo") - writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW") - readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW") - waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject") -) - -// Windows Console constants -const ( - // Console modes - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. - ENABLE_PROCESSED_INPUT = 0x0001 - ENABLE_LINE_INPUT = 0x0002 - ENABLE_ECHO_INPUT = 0x0004 - ENABLE_WINDOW_INPUT = 0x0008 - ENABLE_MOUSE_INPUT = 0x0010 - ENABLE_INSERT_MODE = 0x0020 - ENABLE_QUICK_EDIT_MODE = 0x0040 - ENABLE_EXTENDED_FLAGS = 0x0080 - ENABLE_AUTO_POSITION = 0x0100 - ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200 - - ENABLE_PROCESSED_OUTPUT = 0x0001 - ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002 - ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 - DISABLE_NEWLINE_AUTO_RETURN = 0x0008 - ENABLE_LVB_GRID_WORLDWIDE = 0x0010 - - // Character attributes - // Note: - // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). - // Clearing all foreground or background colors results in black; setting all creates white. - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. - FOREGROUND_BLUE uint16 = 0x0001 - FOREGROUND_GREEN uint16 = 0x0002 - FOREGROUND_RED uint16 = 0x0004 - FOREGROUND_INTENSITY uint16 = 0x0008 - FOREGROUND_MASK uint16 = 0x000F - - BACKGROUND_BLUE uint16 = 0x0010 - BACKGROUND_GREEN uint16 = 0x0020 - BACKGROUND_RED uint16 = 0x0040 - BACKGROUND_INTENSITY uint16 = 0x0080 - BACKGROUND_MASK uint16 = 0x00F0 - - COMMON_LVB_MASK uint16 = 0xFF00 - COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000 - COMMON_LVB_UNDERSCORE uint16 = 0x8000 - - // Input event types - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. - KEY_EVENT = 0x0001 - MOUSE_EVENT = 0x0002 - WINDOW_BUFFER_SIZE_EVENT = 0x0004 - MENU_EVENT = 0x0008 - FOCUS_EVENT = 0x0010 - - // WaitForSingleObject return codes - WAIT_ABANDONED = 0x00000080 - WAIT_FAILED = 0xFFFFFFFF - WAIT_SIGNALED = 0x0000000 - WAIT_TIMEOUT = 0x00000102 - - // WaitForSingleObject wait duration - WAIT_INFINITE = 0xFFFFFFFF - WAIT_ONE_SECOND = 1000 - WAIT_HALF_SECOND = 500 - WAIT_QUARTER_SECOND = 250 -) - -// Windows API Console types -// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD) -// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment -type ( - CHAR_INFO struct { - UnicodeChar uint16 - Attributes uint16 - } - - CONSOLE_CURSOR_INFO struct { - Size uint32 - Visible int32 - } - - CONSOLE_SCREEN_BUFFER_INFO struct { - Size COORD - CursorPosition COORD - Attributes uint16 - Window SMALL_RECT - MaximumWindowSize COORD - } - - COORD struct { - X int16 - Y int16 - } - - SMALL_RECT struct { - Left int16 - Top int16 - Right int16 - Bottom int16 - } - - // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. - INPUT_RECORD struct { - EventType uint16 - KeyEvent KEY_EVENT_RECORD - } - - KEY_EVENT_RECORD struct { - KeyDown int32 - RepeatCount uint16 - VirtualKeyCode uint16 - VirtualScanCode uint16 - UnicodeChar uint16 - ControlKeyState uint32 - } - - WINDOW_BUFFER_SIZE struct { - Size COORD - } -) - -// boolToBOOL converts a Go bool into a Windows int32. -func boolToBOOL(f bool) int32 { - if f { - return int32(1) - } else { - return int32(0) - } -} - -// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx. -func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { - r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) - return checkError(r1, r2, err) -} - -// SetConsoleCursorInfo sets the size and visiblity of the console cursor. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx. -func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { - r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) - return checkError(r1, r2, err) -} - -// SetConsoleCursorPosition location of the console cursor. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx. -func SetConsoleCursorPosition(handle uintptr, coord COORD) error { - r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord)) - use(coord) - return checkError(r1, r2, err) -} - -// GetConsoleMode gets the console mode for given file descriptor -// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx. -func GetConsoleMode(handle uintptr) (mode uint32, err error) { - err = syscall.GetConsoleMode(syscall.Handle(handle), &mode) - return mode, err -} - -// SetConsoleMode sets the console mode for given file descriptor -// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. -func SetConsoleMode(handle uintptr, mode uint32) error { - r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0) - use(mode) - return checkError(r1, r2, err) -} - -// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. -// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx. -func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { - info := CONSOLE_SCREEN_BUFFER_INFO{} - err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)) - if err != nil { - return nil, err - } - return &info, nil -} - -func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error { - r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char))) - use(scrollRect) - use(clipRect) - use(destOrigin) - use(char) - return checkError(r1, r2, err) -} - -// SetConsoleScreenBufferSize sets the size of the console screen buffer. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx. -func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error { - r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord)) - use(coord) - return checkError(r1, r2, err) -} - -// SetConsoleTextAttribute sets the attributes of characters written to the -// console screen buffer by the WriteFile or WriteConsole function. -// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. -func SetConsoleTextAttribute(handle uintptr, attribute uint16) error { - r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0) - use(attribute) - return checkError(r1, r2, err) -} - -// SetConsoleWindowInfo sets the size and position of the console screen buffer's window. -// Note that the size and location must be within and no larger than the backing console screen buffer. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx. -func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error { - r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect))) - use(isAbsolute) - use(rect) - return checkError(r1, r2, err) -} - -// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx. -func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error { - r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion))) - use(buffer) - use(bufferSize) - use(bufferCoord) - return checkError(r1, r2, err) -} - -// ReadConsoleInput reads (and removes) data from the console input buffer. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx. -func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error { - r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count))) - use(buffer) - return checkError(r1, r2, err) -} - -// WaitForSingleObject waits for the passed handle to be signaled. -// It returns true if the handle was signaled; false otherwise. -// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx. -func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) { - r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait))) - switch r1 { - case WAIT_ABANDONED, WAIT_TIMEOUT: - return false, nil - case WAIT_SIGNALED: - return true, nil - } - use(msWait) - return false, err -} - -// String helpers -func (info CONSOLE_SCREEN_BUFFER_INFO) String() string { - return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize) -} - -func (coord COORD) String() string { - return fmt.Sprintf("%v,%v", coord.X, coord.Y) -} - -func (rect SMALL_RECT) String() string { - return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom) -} - -// checkError evaluates the results of a Windows API call and returns the error if it failed. -func checkError(r1, r2 uintptr, err error) error { - // Windows APIs return non-zero to indicate success - if r1 != 0 { - return nil - } - - // Return the error if provided, otherwise default to EINVAL - if err != nil { - return err - } - return syscall.EINVAL -} - -// coordToPointer converts a COORD into a uintptr (by fooling the type system). -func coordToPointer(c COORD) uintptr { - // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass. - return uintptr(*((*uint32)(unsafe.Pointer(&c)))) -} - -// use is a no-op, but the compiler cannot see that it is. -// Calling use(p) ensures that p is kept live until that point. -func use(p interface{}) {} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go deleted file mode 100644 index cbec8f728f..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go +++ /dev/null @@ -1,100 +0,0 @@ -// +build windows - -package winterm - -import "github.com/Azure/go-ansiterm" - -const ( - FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE - BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE -) - -// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the -// request represented by the passed ANSI mode. -func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) { - switch ansiMode { - - // Mode styles - case ansiterm.ANSI_SGR_BOLD: - windowsMode = windowsMode | FOREGROUND_INTENSITY - - case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF: - windowsMode &^= FOREGROUND_INTENSITY - - case ansiterm.ANSI_SGR_UNDERLINE: - windowsMode = windowsMode | COMMON_LVB_UNDERSCORE - - case ansiterm.ANSI_SGR_REVERSE: - inverted = true - - case ansiterm.ANSI_SGR_REVERSE_OFF: - inverted = false - - case ansiterm.ANSI_SGR_UNDERLINE_OFF: - windowsMode &^= COMMON_LVB_UNDERSCORE - - // Foreground colors - case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT: - windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK) - - case ansiterm.ANSI_SGR_FOREGROUND_BLACK: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) - - case ansiterm.ANSI_SGR_FOREGROUND_RED: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED - - case ansiterm.ANSI_SGR_FOREGROUND_GREEN: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN - - case ansiterm.ANSI_SGR_FOREGROUND_YELLOW: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN - - case ansiterm.ANSI_SGR_FOREGROUND_BLUE: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE - - case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE - - case ansiterm.ANSI_SGR_FOREGROUND_CYAN: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE - - case ansiterm.ANSI_SGR_FOREGROUND_WHITE: - windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE - - // Background colors - case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT: - // Black with no intensity - windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK) - - case ansiterm.ANSI_SGR_BACKGROUND_BLACK: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) - - case ansiterm.ANSI_SGR_BACKGROUND_RED: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED - - case ansiterm.ANSI_SGR_BACKGROUND_GREEN: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN - - case ansiterm.ANSI_SGR_BACKGROUND_YELLOW: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN - - case ansiterm.ANSI_SGR_BACKGROUND_BLUE: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE - - case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE - - case ansiterm.ANSI_SGR_BACKGROUND_CYAN: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE - - case ansiterm.ANSI_SGR_BACKGROUND_WHITE: - windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE - } - - return windowsMode, inverted -} - -// invertAttributes inverts the foreground and background colors of a Windows attributes value -func invertAttributes(windowsMode uint16) uint16 { - return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4) -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go deleted file mode 100644 index 3ee06ea728..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build windows - -package winterm - -const ( - horizontal = iota - vertical -) - -func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { - if h.originMode { - sr := h.effectiveSr(info.Window) - return SMALL_RECT{ - Top: sr.top, - Bottom: sr.bottom, - Left: 0, - Right: info.Size.X - 1, - } - } else { - return SMALL_RECT{ - Top: info.Window.Top, - Bottom: info.Window.Bottom, - Left: 0, - Right: info.Size.X - 1, - } - } -} - -// setCursorPosition sets the cursor to the specified position, bounded to the screen size -func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { - position.X = ensureInRange(position.X, window.Left, window.Right) - position.Y = ensureInRange(position.Y, window.Top, window.Bottom) - err := SetConsoleCursorPosition(h.fd, position) - if err != nil { - return err - } - h.logf("Cursor position set: (%d, %d)", position.X, position.Y) - return err -} - -func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error { - return h.moveCursor(vertical, param) -} - -func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error { - return h.moveCursor(horizontal, param) -} - -func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - position := info.CursorPosition - switch moveMode { - case horizontal: - position.X += int16(param) - case vertical: - position.Y += int16(param) - } - - if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { - return err - } - - return nil -} - -func (h *windowsAnsiEventHandler) moveCursorLine(param int) error { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - position := info.CursorPosition - position.X = 0 - position.Y += int16(param) - - if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { - return err - } - - return nil -} - -func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - position := info.CursorPosition - position.X = int16(param) - 1 - - if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { - return err - } - - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go deleted file mode 100644 index 244b5fa25e..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go +++ /dev/null @@ -1,84 +0,0 @@ -// +build windows - -package winterm - -import "github.com/Azure/go-ansiterm" - -func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error { - // Ignore an invalid (negative area) request - if toCoord.Y < fromCoord.Y { - return nil - } - - var err error - - var coordStart = COORD{} - var coordEnd = COORD{} - - xCurrent, yCurrent := fromCoord.X, fromCoord.Y - xEnd, yEnd := toCoord.X, toCoord.Y - - // Clear any partial initial line - if xCurrent > 0 { - coordStart.X, coordStart.Y = xCurrent, yCurrent - coordEnd.X, coordEnd.Y = xEnd, yCurrent - - err = h.clearRect(attributes, coordStart, coordEnd) - if err != nil { - return err - } - - xCurrent = 0 - yCurrent += 1 - } - - // Clear intervening rectangular section - if yCurrent < yEnd { - coordStart.X, coordStart.Y = xCurrent, yCurrent - coordEnd.X, coordEnd.Y = xEnd, yEnd-1 - - err = h.clearRect(attributes, coordStart, coordEnd) - if err != nil { - return err - } - - xCurrent = 0 - yCurrent = yEnd - } - - // Clear remaining partial ending line - coordStart.X, coordStart.Y = xCurrent, yCurrent - coordEnd.X, coordEnd.Y = xEnd, yEnd - - err = h.clearRect(attributes, coordStart, coordEnd) - if err != nil { - return err - } - - return nil -} - -func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error { - region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X} - width := toCoord.X - fromCoord.X + 1 - height := toCoord.Y - fromCoord.Y + 1 - size := uint32(width) * uint32(height) - - if size <= 0 { - return nil - } - - buffer := make([]CHAR_INFO, size) - - char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes} - for i := 0; i < int(size); i++ { - buffer[i] = char - } - - err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion) - if err != nil { - return err - } - - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go deleted file mode 100644 index 2d27fa1d02..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go +++ /dev/null @@ -1,118 +0,0 @@ -// +build windows - -package winterm - -// effectiveSr gets the current effective scroll region in buffer coordinates -func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { - top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom) - bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) - if top >= bottom { - top = window.Top - bottom = window.Bottom - } - return scrollRegion{top: top, bottom: bottom} -} - -func (h *windowsAnsiEventHandler) scrollUp(param int) error { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - sr := h.effectiveSr(info.Window) - return h.scroll(param, sr, info) -} - -func (h *windowsAnsiEventHandler) scrollDown(param int) error { - return h.scrollUp(-param) -} - -func (h *windowsAnsiEventHandler) deleteLines(param int) error { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - start := info.CursorPosition.Y - sr := h.effectiveSr(info.Window) - // Lines cannot be inserted or deleted outside the scrolling region. - if start >= sr.top && start <= sr.bottom { - sr.top = start - return h.scroll(param, sr, info) - } else { - return nil - } -} - -func (h *windowsAnsiEventHandler) insertLines(param int) error { - return h.deleteLines(-param) -} - -// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates. -func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { - h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom) - h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom) - - // Copy from and clip to the scroll region (full buffer width) - scrollRect := SMALL_RECT{ - Top: sr.top, - Bottom: sr.bottom, - Left: 0, - Right: info.Size.X - 1, - } - - // Origin to which area should be copied - destOrigin := COORD{ - X: 0, - Y: sr.top - int16(param), - } - - char := CHAR_INFO{ - UnicodeChar: ' ', - Attributes: h.attributes, - } - - if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { - return err - } - return nil -} - -func (h *windowsAnsiEventHandler) deleteCharacters(param int) error { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - return h.scrollLine(param, info.CursorPosition, info) -} - -func (h *windowsAnsiEventHandler) insertCharacters(param int) error { - return h.deleteCharacters(-param) -} - -// scrollLine scrolls a line horizontally starting at the provided position by a number of columns. -func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { - // Copy from and clip to the scroll region (full buffer width) - scrollRect := SMALL_RECT{ - Top: position.Y, - Bottom: position.Y, - Left: position.X, - Right: info.Size.X - 1, - } - - // Origin to which area should be copied - destOrigin := COORD{ - X: position.X - int16(columns), - Y: position.Y, - } - - char := CHAR_INFO{ - UnicodeChar: ' ', - Attributes: h.attributes, - } - - if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { - return err - } - return nil -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go deleted file mode 100644 index afa7635d77..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build windows - -package winterm - -// AddInRange increments a value by the passed quantity while ensuring the values -// always remain within the supplied min / max range. -func addInRange(n int16, increment int16, min int16, max int16) int16 { - return ensureInRange(n+increment, min, max) -} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go deleted file mode 100644 index 2d40fb75ad..0000000000 --- a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go +++ /dev/null @@ -1,743 +0,0 @@ -// +build windows - -package winterm - -import ( - "bytes" - "log" - "os" - "strconv" - - "github.com/Azure/go-ansiterm" -) - -type windowsAnsiEventHandler struct { - fd uintptr - file *os.File - infoReset *CONSOLE_SCREEN_BUFFER_INFO - sr scrollRegion - buffer bytes.Buffer - attributes uint16 - inverted bool - wrapNext bool - drewMarginByte bool - originMode bool - marginByte byte - curInfo *CONSOLE_SCREEN_BUFFER_INFO - curPos COORD - logf func(string, ...interface{}) -} - -type Option func(*windowsAnsiEventHandler) - -func WithLogf(f func(string, ...interface{})) Option { - return func(w *windowsAnsiEventHandler) { - w.logf = f - } -} - -func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler { - infoReset, err := GetConsoleScreenBufferInfo(fd) - if err != nil { - return nil - } - - h := &windowsAnsiEventHandler{ - fd: fd, - file: file, - infoReset: infoReset, - attributes: infoReset.Attributes, - } - for _, o := range opts { - o(h) - } - - if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { - logFile, _ := os.Create("winEventHandler.log") - logger := log.New(logFile, "", log.LstdFlags) - if h.logf != nil { - l := h.logf - h.logf = func(s string, v ...interface{}) { - l(s, v...) - logger.Printf(s, v...) - } - } else { - h.logf = logger.Printf - } - } - - if h.logf == nil { - h.logf = func(string, ...interface{}) {} - } - - return h -} - -type scrollRegion struct { - top int16 - bottom int16 -} - -// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the -// current cursor position and scroll region settings, in which case it returns -// true. If no special handling is necessary, then it does nothing and returns -// false. -// -// In the false case, the caller should ensure that a carriage return -// and line feed are inserted or that the text is otherwise wrapped. -func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { - if h.wrapNext { - if err := h.Flush(); err != nil { - return false, err - } - h.clearWrap() - } - pos, info, err := h.getCurrentInfo() - if err != nil { - return false, err - } - sr := h.effectiveSr(info.Window) - if pos.Y == sr.bottom { - // Scrolling is necessary. Let Windows automatically scroll if the scrolling region - // is the full window. - if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom { - if includeCR { - pos.X = 0 - h.updatePos(pos) - } - return false, nil - } - - // A custom scroll region is active. Scroll the window manually to simulate - // the LF. - if err := h.Flush(); err != nil { - return false, err - } - h.logf("Simulating LF inside scroll region") - if err := h.scrollUp(1); err != nil { - return false, err - } - if includeCR { - pos.X = 0 - if err := SetConsoleCursorPosition(h.fd, pos); err != nil { - return false, err - } - } - return true, nil - - } else if pos.Y < info.Window.Bottom { - // Let Windows handle the LF. - pos.Y++ - if includeCR { - pos.X = 0 - } - h.updatePos(pos) - return false, nil - } else { - // The cursor is at the bottom of the screen but outside the scroll - // region. Skip the LF. - h.logf("Simulating LF outside scroll region") - if includeCR { - if err := h.Flush(); err != nil { - return false, err - } - pos.X = 0 - if err := SetConsoleCursorPosition(h.fd, pos); err != nil { - return false, err - } - } - return true, nil - } -} - -// executeLF executes a LF without a CR. -func (h *windowsAnsiEventHandler) executeLF() error { - handled, err := h.simulateLF(false) - if err != nil { - return err - } - if !handled { - // Windows LF will reset the cursor column position. Write the LF - // and restore the cursor position. - pos, _, err := h.getCurrentInfo() - if err != nil { - return err - } - h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) - if pos.X != 0 { - if err := h.Flush(); err != nil { - return err - } - h.logf("Resetting cursor position for LF without CR") - if err := SetConsoleCursorPosition(h.fd, pos); err != nil { - return err - } - } - } - return nil -} - -func (h *windowsAnsiEventHandler) Print(b byte) error { - if h.wrapNext { - h.buffer.WriteByte(h.marginByte) - h.clearWrap() - if _, err := h.simulateLF(true); err != nil { - return err - } - } - pos, info, err := h.getCurrentInfo() - if err != nil { - return err - } - if pos.X == info.Size.X-1 { - h.wrapNext = true - h.marginByte = b - } else { - pos.X++ - h.updatePos(pos) - h.buffer.WriteByte(b) - } - return nil -} - -func (h *windowsAnsiEventHandler) Execute(b byte) error { - switch b { - case ansiterm.ANSI_TAB: - h.logf("Execute(TAB)") - // Move to the next tab stop, but preserve auto-wrap if already set. - if !h.wrapNext { - pos, info, err := h.getCurrentInfo() - if err != nil { - return err - } - pos.X = (pos.X + 8) - pos.X%8 - if pos.X >= info.Size.X { - pos.X = info.Size.X - 1 - } - if err := h.Flush(); err != nil { - return err - } - if err := SetConsoleCursorPosition(h.fd, pos); err != nil { - return err - } - } - return nil - - case ansiterm.ANSI_BEL: - h.buffer.WriteByte(ansiterm.ANSI_BEL) - return nil - - case ansiterm.ANSI_BACKSPACE: - if h.wrapNext { - if err := h.Flush(); err != nil { - return err - } - h.clearWrap() - } - pos, _, err := h.getCurrentInfo() - if err != nil { - return err - } - if pos.X > 0 { - pos.X-- - h.updatePos(pos) - h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE) - } - return nil - - case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED: - // Treat as true LF. - return h.executeLF() - - case ansiterm.ANSI_LINE_FEED: - // Simulate a CR and LF for now since there is no way in go-ansiterm - // to tell if the LF should include CR (and more things break when it's - // missing than when it's incorrectly added). - handled, err := h.simulateLF(true) - if handled || err != nil { - return err - } - return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) - - case ansiterm.ANSI_CARRIAGE_RETURN: - if h.wrapNext { - if err := h.Flush(); err != nil { - return err - } - h.clearWrap() - } - pos, _, err := h.getCurrentInfo() - if err != nil { - return err - } - if pos.X != 0 { - pos.X = 0 - h.updatePos(pos) - h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN) - } - return nil - - default: - return nil - } -} - -func (h *windowsAnsiEventHandler) CUU(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CUU: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorVertical(-param) -} - -func (h *windowsAnsiEventHandler) CUD(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CUD: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorVertical(param) -} - -func (h *windowsAnsiEventHandler) CUF(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CUF: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorHorizontal(param) -} - -func (h *windowsAnsiEventHandler) CUB(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CUB: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorHorizontal(-param) -} - -func (h *windowsAnsiEventHandler) CNL(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CNL: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorLine(param) -} - -func (h *windowsAnsiEventHandler) CPL(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CPL: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorLine(-param) -} - -func (h *windowsAnsiEventHandler) CHA(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CHA: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.moveCursorColumn(param) -} - -func (h *windowsAnsiEventHandler) VPA(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("VPA: [[%d]]", param) - h.clearWrap() - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - window := h.getCursorWindow(info) - position := info.CursorPosition - position.Y = window.Top + int16(param) - 1 - return h.setCursorPosition(position, window) -} - -func (h *windowsAnsiEventHandler) CUP(row int, col int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("CUP: [[%d %d]]", row, col) - h.clearWrap() - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - window := h.getCursorWindow(info) - position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1} - return h.setCursorPosition(position, window) -} - -func (h *windowsAnsiEventHandler) HVP(row int, col int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("HVP: [[%d %d]]", row, col) - h.clearWrap() - return h.CUP(row, col) -} - -func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)}) - h.clearWrap() - return nil -} - -func (h *windowsAnsiEventHandler) DECOM(enable bool) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)}) - h.clearWrap() - h.originMode = enable - return h.CUP(1, 1) -} - -func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)}) - h.clearWrap() - if err := h.ED(2); err != nil { - return err - } - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - targetWidth := int16(80) - if use132 { - targetWidth = 132 - } - if info.Size.X < targetWidth { - if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { - h.logf("set buffer failed: %v", err) - return err - } - } - window := info.Window - window.Left = 0 - window.Right = targetWidth - 1 - if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { - h.logf("set window failed: %v", err) - return err - } - if info.Size.X > targetWidth { - if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { - h.logf("set buffer failed: %v", err) - return err - } - } - return SetConsoleCursorPosition(h.fd, COORD{0, 0}) -} - -func (h *windowsAnsiEventHandler) ED(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("ED: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - - // [J -- Erases from the cursor to the end of the screen, including the cursor position. - // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position. - // [2J -- Erases the complete display. The cursor does not move. - // Notes: - // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles - - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - var start COORD - var end COORD - - switch param { - case 0: - start = info.CursorPosition - end = COORD{info.Size.X - 1, info.Size.Y - 1} - - case 1: - start = COORD{0, 0} - end = info.CursorPosition - - case 2: - start = COORD{0, 0} - end = COORD{info.Size.X - 1, info.Size.Y - 1} - } - - err = h.clearRange(h.attributes, start, end) - if err != nil { - return err - } - - // If the whole buffer was cleared, move the window to the top while preserving - // the window-relative cursor position. - if param == 2 { - pos := info.CursorPosition - window := info.Window - pos.Y -= window.Top - window.Bottom -= window.Top - window.Top = 0 - if err := SetConsoleCursorPosition(h.fd, pos); err != nil { - return err - } - if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { - return err - } - } - - return nil -} - -func (h *windowsAnsiEventHandler) EL(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("EL: [%v]", strconv.Itoa(param)) - h.clearWrap() - - // [K -- Erases from the cursor to the end of the line, including the cursor position. - // [1K -- Erases from the beginning of the line to the cursor, including the cursor position. - // [2K -- Erases the complete line. - - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - var start COORD - var end COORD - - switch param { - case 0: - start = info.CursorPosition - end = COORD{info.Size.X, info.CursorPosition.Y} - - case 1: - start = COORD{0, info.CursorPosition.Y} - end = info.CursorPosition - - case 2: - start = COORD{0, info.CursorPosition.Y} - end = COORD{info.Size.X, info.CursorPosition.Y} - } - - err = h.clearRange(h.attributes, start, end) - if err != nil { - return err - } - - return nil -} - -func (h *windowsAnsiEventHandler) IL(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("IL: [%v]", strconv.Itoa(param)) - h.clearWrap() - return h.insertLines(param) -} - -func (h *windowsAnsiEventHandler) DL(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("DL: [%v]", strconv.Itoa(param)) - h.clearWrap() - return h.deleteLines(param) -} - -func (h *windowsAnsiEventHandler) ICH(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("ICH: [%v]", strconv.Itoa(param)) - h.clearWrap() - return h.insertCharacters(param) -} - -func (h *windowsAnsiEventHandler) DCH(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("DCH: [%v]", strconv.Itoa(param)) - h.clearWrap() - return h.deleteCharacters(param) -} - -func (h *windowsAnsiEventHandler) SGR(params []int) error { - if err := h.Flush(); err != nil { - return err - } - strings := []string{} - for _, v := range params { - strings = append(strings, strconv.Itoa(v)) - } - - h.logf("SGR: [%v]", strings) - - if len(params) <= 0 { - h.attributes = h.infoReset.Attributes - h.inverted = false - } else { - for _, attr := range params { - - if attr == ansiterm.ANSI_SGR_RESET { - h.attributes = h.infoReset.Attributes - h.inverted = false - continue - } - - h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr)) - } - } - - attributes := h.attributes - if h.inverted { - attributes = invertAttributes(attributes) - } - err := SetConsoleTextAttribute(h.fd, attributes) - if err != nil { - return err - } - - return nil -} - -func (h *windowsAnsiEventHandler) SU(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("SU: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.scrollUp(param) -} - -func (h *windowsAnsiEventHandler) SD(param int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("SD: [%v]", []string{strconv.Itoa(param)}) - h.clearWrap() - return h.scrollDown(param) -} - -func (h *windowsAnsiEventHandler) DA(params []string) error { - h.logf("DA: [%v]", params) - // DA cannot be implemented because it must send data on the VT100 input stream, - // which is not available to go-ansiterm. - return nil -} - -func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error { - if err := h.Flush(); err != nil { - return err - } - h.logf("DECSTBM: [%d, %d]", top, bottom) - - // Windows is 0 indexed, Linux is 1 indexed - h.sr.top = int16(top - 1) - h.sr.bottom = int16(bottom - 1) - - // This command also moves the cursor to the origin. - h.clearWrap() - return h.CUP(1, 1) -} - -func (h *windowsAnsiEventHandler) RI() error { - if err := h.Flush(); err != nil { - return err - } - h.logf("RI: []") - h.clearWrap() - - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - sr := h.effectiveSr(info.Window) - if info.CursorPosition.Y == sr.top { - return h.scrollDown(1) - } - - return h.moveCursorVertical(-1) -} - -func (h *windowsAnsiEventHandler) IND() error { - h.logf("IND: []") - return h.executeLF() -} - -func (h *windowsAnsiEventHandler) Flush() error { - h.curInfo = nil - if h.buffer.Len() > 0 { - h.logf("Flush: [%s]", h.buffer.Bytes()) - if _, err := h.buffer.WriteTo(h.file); err != nil { - return err - } - } - - if h.wrapNext && !h.drewMarginByte { - h.logf("Flush: drawing margin byte '%c'", h.marginByte) - - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return err - } - - charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}} - size := COORD{1, 1} - position := COORD{0, 0} - region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y} - if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil { - return err - } - h.drewMarginByte = true - } - return nil -} - -// cacheConsoleInfo ensures that the current console screen information has been queried -// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos. -func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { - if h.curInfo == nil { - info, err := GetConsoleScreenBufferInfo(h.fd) - if err != nil { - return COORD{}, nil, err - } - h.curInfo = info - h.curPos = info.CursorPosition - } - return h.curPos, h.curInfo, nil -} - -func (h *windowsAnsiEventHandler) updatePos(pos COORD) { - if h.curInfo == nil { - panic("failed to call getCurrentInfo before calling updatePos") - } - h.curPos = pos -} - -// clearWrap clears the state where the cursor is in the margin -// waiting for the next character before wrapping the line. This must -// be done before most operations that act on the cursor. -func (h *windowsAnsiEventHandler) clearWrap() { - h.wrapNext = false - h.drewMarginByte = false -} diff --git a/vendor/github.com/skycoin/dmsg/.gitignore b/vendor/github.com/skycoin/dmsg/.gitignore index cd9864fccf..553a6e7917 100644 --- a/vendor/github.com/skycoin/dmsg/.gitignore +++ b/vendor/github.com/skycoin/dmsg/.gitignore @@ -19,4 +19,3 @@ bin/ /dmsgpty-ui /hello.txt -/integration/integration-pids.csv diff --git a/vendor/github.com/skycoin/dmsg/Makefile b/vendor/github.com/skycoin/dmsg/Makefile index 75440c6f1e..21d6c3f4d0 100644 --- a/vendor/github.com/skycoin/dmsg/Makefile +++ b/vendor/github.com/skycoin/dmsg/Makefile @@ -1,8 +1,4 @@ -ifeq ($(OS),Windows_NT) - SHELL := pwsh -else - SHELL := /bin/bash -endif +SHELL := /bin/bash .DEFAULT_GOAL := help .PHONY : check lint install-linters dep test build @@ -10,21 +6,12 @@ endif VERSION := $(shell git describe --always) RFC_3339 := "+%Y-%m-%dT%H:%M:%SZ" +DATE := $(shell date -u $(RFC_3339)) COMMIT := $(shell git rev-list -1 HEAD) -ifeq ($(OS),Windows_NT) - BIN := .\bin - BIN_DIR?=.\bin - CMD_DIR := .\cmd - DATE := $(shell powershell -Command date -u ${RFC_3339}) -else - BIN := ${PWD}/bin - BIN_DIR?=./bin - CMD_DIR := ./cmd - DATE := $(shell date -u ${RFC_3339}) -endif - +BIN := ${PWD}/bin OPTS?=GO111MODULE=on +BIN_DIR?=./bin TEST_OPTS:=-tags no_ci -cover -timeout=5m @@ -80,11 +67,7 @@ install: ## Install `dmsg-discovery`, `dmsg-server`, `dmsgget`,`dmsgpty-cli`, `d ${OPTS} go install ${BUILD_OPTS} ./cmd/* build: ## Build binaries into ./bin - mkdir -p ${BIN}; go build ${BUILD_OPTS} -o ${BIN} ${CMD_DIR}/* - -build-windows: - powershell -Command new-item ${BIN} -itemtype directory -force - powershell 'Get-ChildItem ${CMD_DIR} | % { go build ${BUILD_OPTS} -o ${BIN} $$_.FullName }' + mkdir -p ${BIN}; go build ${BUILD_OPTS} -o ${BIN} ./cmd/* build-deploy: ## Build for deployment Docker images go build -tags netgo ${BUILD_OPTS_DEPLOY} -o /release/dmsg-discovery ./cmd/dmsg-discovery @@ -122,11 +105,5 @@ attach-pty: ## Attach local dmsgpty tmux session. stop-all: stop-pty stop-dmsg stop-db ## Stop all local tmux sessions. -integration-windows-start: - powershell -Command .\integration\integration.ps1 start - -integration-windows-stop: - powershell -Command .\integration\integration.ps1 stop - help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/vendor/github.com/skycoin/dmsg/client.go b/vendor/github.com/skycoin/dmsg/client.go index 7bec26aaf6..ade841f210 100644 --- a/vendor/github.com/skycoin/dmsg/client.go +++ b/vendor/github.com/skycoin/dmsg/client.go @@ -106,7 +106,7 @@ func NewClient(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Conf c.EntityCommon.init(pk, sk, dc, log, conf.UpdateInterval) // Init callback: on set session. - c.EntityCommon.setSessionCallback = func(ctx context.Context) error { + c.EntityCommon.setSessionCallback = func(ctx context.Context, sessionCount int) error { if err := c.EntityCommon.updateClientEntry(ctx, c.done); err != nil { return err } @@ -118,8 +118,8 @@ func NewClient(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Conf } // Init callback: on delete session. - c.EntityCommon.delSessionCallback = func(ctx context.Context) error { - err := c.EntityCommon.delClientEntry(ctx, c.done) + c.EntityCommon.delSessionCallback = func(ctx context.Context, sessionCount int) error { + err := c.EntityCommon.updateClientEntry(ctx, c.done) return err } @@ -149,6 +149,9 @@ func (ce *Client) Serve(ctx context.Context) { } }(cancellabelCtx) + // Ensure we start updateClientEntryLoop once only. + updateEntryLoopOnce := new(sync.Once) + for { if isClosed(ce.done) { return @@ -194,6 +197,9 @@ func (ce *Client) Serve(ctx context.Context) { } time.Sleep(serveWait) } + + // Only start the update entry loop once we have at least one session established. + updateEntryLoopOnce.Do(func() { go ce.updateClientEntryLoop(cancellabelCtx, ce.done) }) } } } @@ -233,9 +239,9 @@ func (ce *Client) Close() error { Info("Session closed.") } ce.sessions = make(map[cipher.PubKey]*SessionCommon) + ce.log.Info("All sessions closed.") ce.sessionsMx.Unlock() - ce.delSession(context.Background(), ce.pk) ce.porter.CloseAll(ce.log) }) diff --git a/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go b/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go index 6fbaa75e56..02d0490845 100644 --- a/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go +++ b/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go @@ -32,6 +32,7 @@ const ( // ServiceFlags represents common flags which are shared across services. type ServiceFlags struct { MetricsAddr string + HTTPAddr string Syslog string SyslogNet string LogLevel string @@ -76,6 +77,7 @@ func (sf *ServiceFlags) Init(rootCmd *cobra.Command, defaultTag, defaultConf str // flags rootCmd.Flags().StringVarP(&sf.MetricsAddr, "metrics", "m", sf.MetricsAddr, "address to serve metrics API from") + rootCmd.Flags().StringVarP(&sf.HTTPAddr, "http", "p", ":8082", "address to serve http API for health endpoint") rootCmd.Flags().StringVar(&sf.Syslog, "syslog", sf.Syslog, "address in which to dial to syslog server") rootCmd.Flags().StringVar(&sf.SyslogNet, "syslog-net", sf.SyslogNet, "network in which to dial to syslog server") rootCmd.Flags().StringVar(&sf.LogLevel, "syslog-lvl", sf.LogLevel, "minimum log level to report") diff --git a/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go b/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go index a8b119e08c..56291a4822 100644 --- a/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go +++ b/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go @@ -16,7 +16,7 @@ func SignalContext(ctx context.Context, log logrus.FieldLogger) (context.Context ctx, cancel := context.WithCancel(ctx) - ch := make(chan os.Signal, 1) + ch := make(chan os.Signal) listenSigs := listenSignals() signal.Notify(ch, listenSigs...) diff --git a/vendor/github.com/skycoin/dmsg/disc/client.go b/vendor/github.com/skycoin/dmsg/disc/client.go index 7aa27a8af3..ba1fa19abe 100644 --- a/vendor/github.com/skycoin/dmsg/disc/client.go +++ b/vendor/github.com/skycoin/dmsg/disc/client.go @@ -25,7 +25,6 @@ type APIClient interface { Entry(context.Context, cipher.PubKey) (*Entry, error) PostEntry(context.Context, *Entry) error PutEntry(context.Context, cipher.SecKey, *Entry) error - DelEntry(context.Context, *Entry) error AvailableServers(context.Context) ([]*Entry, error) } @@ -108,62 +107,8 @@ func (c *httpClient) PostEntry(ctx context.Context, e *Entry) error { req.Header.Set("Content-Type", "application/json") // Since v0.3.0 visors send ?timeout=true, before v0.3.0 do not. - // Since v0.5.0 visors send do not send ?timeout=true anymore. - q := req.URL.Query() - req.URL.RawQuery = q.Encode() - - req = req.WithContext(ctx) - - resp, err := c.client.Do(req) - if resp != nil { - defer func() { - if err := resp.Body.Close(); err != nil { - log.WithError(err).Warn("Failed to close response body.") - } - }() - } - if err != nil { - log.WithError(err).Error("Failed to perform request.") - return err - } - - if resp.StatusCode != http.StatusOK { - var httpResponse HTTPMessage - - bodyBytes, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - err = json.Unmarshal(bodyBytes, &httpResponse) - if err != nil { - return err - } - log.WithField("resp_body", httpResponse.Message). - WithField("resp_status", resp.StatusCode). - Error() - return errFromString(httpResponse.Message) - } - return nil -} - -// DelEntry creates a new Entry. -func (c *httpClient) DelEntry(ctx context.Context, e *Entry) error { - endpoint := c.address + "/dmsg-discovery/entry" - log := log.WithField("endpoint", endpoint) - - marshaledEntry, err := json.Marshal(e) - if err != nil { - return err - } - - req, err := http.NewRequest(http.MethodDelete, endpoint, bytes.NewBuffer(marshaledEntry)) - if err != nil { - return err - } - - req.Header.Set("Content-Type", "application/json") - q := req.URL.Query() + q.Add("timeout", "true") req.URL.RawQuery = q.Encode() req = req.WithContext(ctx) diff --git a/vendor/github.com/skycoin/dmsg/disc/http_message.go b/vendor/github.com/skycoin/dmsg/disc/http_message.go index 30c7aa6ed1..7336bf6973 100644 --- a/vendor/github.com/skycoin/dmsg/disc/http_message.go +++ b/vendor/github.com/skycoin/dmsg/disc/http_message.go @@ -9,7 +9,6 @@ import ( var ( MsgEntrySet = HTTPMessage{Code: http.StatusOK, Message: "wrote a new entry"} MsgEntryUpdated = HTTPMessage{Code: http.StatusOK, Message: "wrote new entry iteration"} - MsgEntryDeleted = HTTPMessage{Code: http.StatusOK, Message: "deleted entry"} ) // HTTPMessage represents a message to be returned as an http response diff --git a/vendor/github.com/skycoin/dmsg/disc/testing.go b/vendor/github.com/skycoin/dmsg/disc/testing.go index 9fc87fe277..a697319edc 100644 --- a/vendor/github.com/skycoin/dmsg/disc/testing.go +++ b/vendor/github.com/skycoin/dmsg/disc/testing.go @@ -35,12 +35,6 @@ func (m *mockClient) entry(pk cipher.PubKey) (Entry, bool) { return e, ok } -func (m *mockClient) delEntry(pk cipher.PubKey) { - m.mx.Lock() - defer m.mx.Unlock() - delete(m.entries, pk) -} - func (m *mockClient) setEntry(entry Entry) { m.mx.Lock() defer m.mx.Unlock() @@ -93,12 +87,6 @@ func (m *mockClient) PostEntry(_ context.Context, entry *Entry) error { return nil } -// DelEntry returns the mock client static public key associated entry -func (m *mockClient) DelEntry(_ context.Context, entry *Entry) error { - m.delEntry(entry.Static) - return nil -} - // PutEntry updates a previously set entry func (m *mockClient) PutEntry(ctx context.Context, sk cipher.SecKey, e *Entry) error { e.Sequence++ diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go index ac71769a63..c2d7e01756 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go @@ -6,9 +6,13 @@ import ( "io" "net" "os" + "os/signal" + "syscall" + "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" + terminal "golang.org/x/term" "github.com/skycoin/dmsg/cipher" ) @@ -25,7 +29,7 @@ func DefaultCLI() CLI { return CLI{ Log: logging.MustGetLogger("dmsgpty-cli"), Net: DefaultCLINet, - Addr: DefaultCLIAddr(), + Addr: DefaultCLIAddr, } } @@ -91,7 +95,7 @@ func (cli *CLI) prepareConn() (net.Conn, error) { cli.Net = DefaultCLINet } if cli.Addr == "" { - cli.Addr = DefaultCLIAddr() + cli.Addr = DefaultCLIAddr } cli.Log. @@ -105,6 +109,26 @@ func (cli *CLI) prepareConn() (net.Conn, error) { return conn, nil } +// prepareStdin sets stdin to raw mode and provides a function to restore the original state. +func (cli *CLI) prepareStdin() (restore func(), err error) { + var oldState *terminal.State + if oldState, err = terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { + cli.Log. + WithError(err). + Warn("Failed to set stdin to raw mode.") + return + } + restore = func() { + // Attempt to restore state. + if err := terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { + cli.Log. + WithError(err). + Error("Failed to restore original stdin state.") + } + } + return +} + // servePty serves a pty connection via the dmsgpty-host. func (cli *CLI) servePty(ctx context.Context, ptyC *PtyClient, cmd string, args []string) error { ctx, cancel := context.WithCancel(ctx) @@ -143,3 +167,28 @@ func (cli *CLI) servePty(ctx context.Context, ptyC *PtyClient, cmd string, args return nil } + +// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. +func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGWINCH) + for { + select { + case <-ctx.Done(): + return nil + case <-ch: + winSize, err := getPtySize(os.Stdin) + if err != nil { + return fmt.Errorf("failed to obtain window size: %v", err) + } + if err := ptyC.SetPtySize(winSize); err != nil { + return fmt.Errorf("failed to set remote window size: %v", err) + } + } + } +} + +// getPtySize obtains the size of the local terminal. +func getPtySize(t *os.File) (*pty.Winsize, error) { + return pty.GetsizeFull(t) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go deleted file mode 100644 index b5b3277d65..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go +++ /dev/null @@ -1,63 +0,0 @@ -//+build !windows - -package dmsgpty - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/creack/pty" - "golang.org/x/crypto/ssh/terminal" -) - -// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. -func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { - ch := make(chan os.Signal, 1) - signal.Notify(ch, syscall.SIGWINCH) - for { - select { - case <-ctx.Done(): - return nil - case <-ch: - winSize, err := getPtySize(os.Stdin) - if err != nil { - return fmt.Errorf("failed to obtain window size: %v", err) - } - ws, err := NewWinSize(winSize) - if err != nil { - return fmt.Errorf("failed to convert pty size to WinSize: %v", err) - } - if err := ptyC.SetPtySize(ws); err != nil { - return fmt.Errorf("failed to set remote window size: %v", err) - } - } - } -} - -// getPtySize obtains the size of the local terminal. -func getPtySize(t *os.File) (*pty.Winsize, error) { - return pty.GetsizeFull(t) -} - -// prepareStdin sets stdin to raw mode and provides a function to restore the original state. -func (cli *CLI) prepareStdin() (restore func(), err error) { - var oldState *terminal.State - if oldState, err = terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { - cli.Log. - WithError(err). - Warn("Failed to set stdin to raw mode.") - return - } - restore = func() { - // Attempt to restore state. - if err = terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { - cli.Log. - WithError(err). - Error("Failed to restore original stdin state.") - } - } - return -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go deleted file mode 100644 index 01938d0cca..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go +++ /dev/null @@ -1,44 +0,0 @@ -//+build windows - -package dmsgpty - -import ( - "context" - "sync" - "time" - - "github.com/ActiveState/termtest/conpty" -) - -// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. -func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { - t := time.NewTicker(1 * time.Second) - mu := sync.RWMutex{} - var initialSize *WinSize - for { - select { - case <-ctx.Done(): - t.Stop() - return nil - case <-t.C: - mu.Lock() - size, err := getSize() - if err == nil { - if initialSize == nil { - initialSize = size - } else if initialSize.X != size.X || initialSize.Y != size.Y { - initialSize = size - if err = ptyC.SetPtySize(initialSize); err != nil { - mu.Unlock() - return err - } - } - } - mu.Unlock() - } - } -} - -func (cli *CLI) prepareStdin() (restore func(), err error) { - return conpty.InitTerminal(true) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go b/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go index 03ded6f813..84f2a7a2d5 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go @@ -3,9 +3,6 @@ package dmsgpty import ( "fmt" "os" - "path/filepath" - "runtime" - "strings" "github.com/skycoin/dmsg" ) @@ -29,7 +26,7 @@ func DefaultConfig() Config { DmsgSessions: dmsg.DefaultMinSessions, DmsgPort: DefaultPort, CLINet: DefaultCLINet, - CLIAddr: DefaultCLIAddr(), + CLIAddr: DefaultCLIAddr, } } @@ -43,50 +40,3 @@ func WriteConfig(conf Config, path string) error { enc.SetIndent("", " ") return enc.Encode(&conf) } - -func findStringsEnclosedBy(str string, sep string, result []string, lastIndex int) ([]string, int) { - s := strings.Index(str, sep) - if s == -1 { - return result, lastIndex - } - newS := str[s+len(sep):] - e := strings.Index(newS, sep) - if e == -1 { - lastIndex += len(sep) - return result, lastIndex - } - res := newS[:e] - if res != "" { - result = append(result, res) - } - last := s + len(res) + len(sep) - if lastIndex == -1 { - lastIndex = last - } else { - lastIndex += last - } - str = str[last:] - return findStringsEnclosedBy(str, sep, result, lastIndex) -} - -// ParseWindowsEnv finds '%'-enclosed windows env in json string -func ParseWindowsEnv(cliAddr string) string { - if runtime.GOOS == "windows" { - var res []string - results, lastIndex := findStringsEnclosedBy(cliAddr, "%", res, -1) - if len(results) > 0 { - paths := make([]string, len(results)+1) - for i, s := range results { - pth := os.Getenv(strings.ToUpper(s)) - if pth != "" { - paths[i] = pth - } - } - paths[len(paths)-1] = strings.Replace(cliAddr[lastIndex:], string(filepath.Separator), "", 1) - cliAddr = filepath.Join(paths...) - _ = strings.ReplaceAll(cliAddr, `\`, `\\`) - return cliAddr - } - } - return cliAddr -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const.go index 4497d75379..74bec2933d 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/const.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const.go @@ -12,3 +12,15 @@ const ( WhitelistRPCName = "whitelist" WhitelistURI = "dmsgpty/whitelist" ) + +// Constants related to CLI. +const ( + DefaultCLINet = "unix" + DefaultCLIAddr = "/tmp/dmsgpty.sock" +) + +// Constants related to dmsg. +const ( + DefaultPort = uint16(22) + DefaultCmd = "/bin/bash" +) diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go deleted file mode 100644 index 8616378c7e..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go +++ /dev/null @@ -1,24 +0,0 @@ -//+build !windows - -package dmsgpty - -import ( - "os" - "path/filepath" -) - -// Constants related to CLI. -const ( - DefaultCLINet = "unix" -) - -// Constants related to dmsg. -const ( - DefaultPort = uint16(22) - DefaultCmd = "/bin/bash" -) - -// DefaultCLIAddr gets the default cli address (temp address) -func DefaultCLIAddr() string { - return filepath.Join(os.TempDir(), "dmsgpty.sock") -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go deleted file mode 100644 index 6b5ce832e7..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -//+build windows - -package dmsgpty - -import ( - "os" - "path/filepath" -) - -const ( - DefaultCLINet = "unix" -) - -// Constants related to dmsg. -const ( - DefaultPort = uint16(22) - DefaultCmd = `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` -) - -// DefaultCLIAddr gets the default cli address -func DefaultCLIAddr() string { - homedir, err := os.UserHomeDir() - if err != nil { - homedir = os.TempDir() - } - return filepath.Join(homedir, "dmsgpty.sock") -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/host.go b/vendor/github.com/skycoin/dmsg/dmsgpty/host.go index 51f1df01f9..98b6bc00a7 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/host.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/host.go @@ -46,7 +46,7 @@ func (h *Host) ServeCLI(ctx context.Context, lis net.Listener) error { _ = lis.Close() //nolint:errcheck }() - log := logging.MustGetLogger("dmsg_pty:cli-server") + log := logging.MustGetLogger("dmsgpty:cli-server") mux := cliEndpoints(h) @@ -86,11 +86,9 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { return err } - log := logging.MustGetLogger("dmsg_pty") - go func() { <-ctx.Done() - log. + h.log(). WithError(lis.Close()). Info("Serve() ended.") }() @@ -98,7 +96,7 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { for { stream, err := lis.AcceptStream() if err != nil { - log := log.WithError(err) + log := h.log().WithError(err) if err, ok := err.(net.Error); ok && err.Temporary() { log.Warn("Failed to accept dmsg.Stream with temporary error, continuing...") continue @@ -113,7 +111,7 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { } rPK := stream.RawRemoteAddr().PK - log := log.WithField("remote_pk", rPK.String()) + log := h.log().WithField("remote_pk", rPK.String()) log.Info("Processing dmsg.Stream...") if !h.authorize(log, rPK) { diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty.go similarity index 80% rename from vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go rename to vendor/github.com/skycoin/dmsg/dmsgpty/pty.go index b7dc14d122..2122a00800 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty.go @@ -1,5 +1,3 @@ -//+build !windows - package dmsgpty import ( @@ -28,6 +26,27 @@ func NewPty() *Pty { return new(Pty) } +// Start runs a command with the given command name, args and optional window size. +func (s *Pty) Start(name string, args []string, size *pty.Winsize) error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty != nil { + return ErrPtyAlreadyRunning + } + + cmd := exec.Command(name, args...) //nolint:gosec + cmd.Env = os.Environ() + + f, err := pty.StartWithSize(cmd, size) //nolint:gosec + if err != nil { + return err + } + + s.pty = f + return nil +} + // Stop stops the running command and closes the pty. func (s *Pty) Stop() error { s.mx.Lock() @@ -66,37 +85,8 @@ func (s *Pty) Write(b []byte) (int, error) { return s.pty.Write(b) } -// Start runs a command with the given command name, args and optional window size. -func (s *Pty) Start(name string, args []string, size *WinSize) error { - s.mx.Lock() - defer s.mx.Unlock() - - if s.pty != nil { - return ErrPtyAlreadyRunning - } - - cmd := exec.Command(name, args...) //nolint:gosec - cmd.Env = os.Environ() - var sz *pty.Winsize - var err error - - if size == nil { - sz = nil - } else { - sz = size.PtySize() - } - - f, err := pty.StartWithSize(cmd, sz) //nolint:gosec - if err != nil { - return err - } - - s.pty = f - return nil -} - // SetPtySize sets the pty size. -func (s *Pty) SetPtySize(size *WinSize) error { +func (s *Pty) SetPtySize(size *pty.Winsize) error { s.mx.RLock() defer s.mx.RUnlock() @@ -104,7 +94,5 @@ func (s *Pty) SetPtySize(size *WinSize) error { return ErrPtyNotRunning } - sz := size.PtySize() - - return pty.Setsize(s.pty, sz) + return pty.Setsize(s.pty, size) } diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go index 92deb1abfa..af94e5d9df 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go @@ -4,8 +4,10 @@ import ( "fmt" "io" "net/rpc" + "os" "sync" + "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" @@ -70,6 +72,21 @@ func (sc *PtyClient) close() (closed bool) { return closed } +// Start starts the pty. +func (sc *PtyClient) Start(name string, arg ...string) error { + size, err := pty.GetsizeFull(os.Stdin) + if err != nil { + sc.log.WithError(err).Warn("failed to obtain terminal size") + size = nil + } + return sc.StartWithSize(name, arg, size) +} + +// StartWithSize starts the pty with a specified size. +func (sc *PtyClient) StartWithSize(name string, arg []string, size *pty.Winsize) error { + return sc.call("Start", &CommandReq{Name: name, Arg: arg, Size: size}, &empty) +} + // Stop stops the pty. func (sc *PtyClient) Stop() error { return sc.call("Stop", &empty, &empty) @@ -90,6 +107,11 @@ func (sc *PtyClient) Write(b []byte) (int, error) { return n, processRPCError(err) } +// SetPtySize sets the pty size. +func (sc *PtyClient) SetPtySize(size *pty.Winsize) error { + return sc.call("SetPtySize", size, &empty) +} + func (*PtyClient) rpcMethod(m string) string { return PtyRPCName + "." + m } @@ -103,22 +125,3 @@ func (sc *PtyClient) call(method string, args, reply interface{}) error { return call.Error } } - -// Start starts the pty. -func (sc *PtyClient) Start(name string, arg ...string) error { - return sc.call("Start", &CommandReq{ - Name: name, - Arg: arg, - Size: nil, - }, &empty) -} - -// StartWithSize starts the pty with a specified size. -func (sc *PtyClient) StartWithSize(name string, arg []string, c *WinSize) error { - return sc.call("Start", &CommandReq{Name: name, Arg: arg, Size: c}, &empty) -} - -// SetPtySize sets the pty size. -func (sc *PtyClient) SetPtySize(size *WinSize) error { - return sc.call("SetPtySize", size, &empty) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go deleted file mode 100644 index 36965a440d..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go +++ /dev/null @@ -1,31 +0,0 @@ -//+build windows - -package dmsgpty - -import ( - "errors" - - "golang.org/x/sys/windows" -) - -// getSize gets windows terminal size -func getSize() (*WinSize, error) { - var bufInfo windows.ConsoleScreenBufferInfo - c, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) - if err != nil { - return nil, err - } - if err = windows.GetConsoleScreenBufferInfo(c, &bufInfo); err != nil { - if errors.Is(err, windows.ERROR_INVALID_HANDLE) { - return &WinSize{ - X: 80, - Y: 30, - }, nil - } - return nil, err - } - return NewWinSize(&windows.Coord{ - X: bufInfo.Window.Right - bufInfo.Window.Left + 1, - Y: bufInfo.Window.Bottom - bufInfo.Window.Top + 1, - }) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go index cf6aab8801..abb0508ec5 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go @@ -1,12 +1,8 @@ package dmsgpty -// WinSize wraps around pty.Winsize and *windows.Coord -type WinSize struct { - X uint16 - Y uint16 - Rows uint16 - Cols uint16 -} +import ( + "github.com/creack/pty" +) // PtyGateway represents a pty gateway, hosted by the pty.SessionServer type PtyGateway interface { @@ -14,14 +10,7 @@ type PtyGateway interface { Stop(_, _ *struct{}) error Read(reqN *int, respB *[]byte) error Write(reqB *[]byte, respN *int) error - SetPtySize(size *WinSize, _ *struct{}) error -} - -// CommandReq represents a pty command. -type CommandReq struct { - Name string - Arg []string - Size *WinSize + SetPtySize(size *pty.Winsize, _ *struct{}) error } // LocalPtyGateway is the gateway to a local pty. @@ -34,6 +23,18 @@ func NewPtyGateway(ses *Pty) PtyGateway { return &LocalPtyGateway{ses: ses} } +// CommandReq represents a pty command. +type CommandReq struct { + Name string + Arg []string + Size *pty.Winsize +} + +// Start starts the local pty. +func (g *LocalPtyGateway) Start(req *CommandReq, _ *struct{}) error { + return g.ses.Start(req.Name, req.Arg, req.Size) +} + // Stop stops the local pty. func (g *LocalPtyGateway) Stop(_, _ *struct{}) error { return g.ses.Stop() @@ -47,11 +48,6 @@ func (g *LocalPtyGateway) Read(reqN *int, respB *[]byte) error { return err } -// Start starts the local pty. -func (g *LocalPtyGateway) Start(req *CommandReq, _ *struct{}) error { - return g.ses.Start(req.Name, req.Arg, req.Size) -} - // Write writes to the local pty. func (g *LocalPtyGateway) Write(wb *[]byte, n *int) error { var err error @@ -60,15 +56,10 @@ func (g *LocalPtyGateway) Write(wb *[]byte, n *int) error { } // SetPtySize sets the local pty's window size. -func (g *LocalPtyGateway) SetPtySize(size *WinSize, _ *struct{}) error { +func (g *LocalPtyGateway) SetPtySize(size *pty.Winsize, _ *struct{}) error { return g.ses.SetPtySize(size) } -// SetPtySize sets the remote pty's window size. -func (g *ProxiedPtyGateway) SetPtySize(size *WinSize, _ *struct{}) error { - return g.ptyC.SetPtySize(size) -} - // ProxiedPtyGateway is an RPC gateway for a remote pty. type ProxiedPtyGateway struct { ptyC *PtyClient @@ -103,3 +94,8 @@ func (g *ProxiedPtyGateway) Write(reqB *[]byte, respN *int) error { *respN, err = g.ptyC.Write(*reqB) return err } + +// SetPtySize sets the remote pty's window size. +func (g *ProxiedPtyGateway) SetPtySize(size *pty.Winsize, _ *struct{}) error { + return g.ptyC.SetPtySize(size) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go deleted file mode 100644 index 4176d90448..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go +++ /dev/null @@ -1,32 +0,0 @@ -//+build !windows - -package dmsgpty - -import ( - "errors" - - "github.com/creack/pty" -) - -// NewWinSize creates a new WinSize wrapper object -func NewWinSize(w *pty.Winsize) (*WinSize, error) { - if w == nil { - return nil, errors.New("pty size cannot be nil") - } - return &WinSize{ - X: w.X, - Y: w.Y, - Rows: w.Rows, - Cols: w.Cols, - }, nil -} - -// PtySize returns *pty.Winsize -func (w *WinSize) PtySize() *pty.Winsize { - return &pty.Winsize{ - Rows: w.Rows, - Cols: w.Cols, - X: w.X, - Y: w.Y, - } -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go deleted file mode 100644 index 199c01b3ee..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go +++ /dev/null @@ -1,28 +0,0 @@ -//+build windows - -package dmsgpty - -import ( - "errors" - - "golang.org/x/sys/windows" -) - -// NewWinSize creates a new WinSize object -func NewWinSize(w *windows.Coord) (*WinSize, error) { - if w == nil { - return nil, errors.New("pty size is nil") - } - return &WinSize{ - X: uint16(w.X), - Y: uint16(w.Y), - }, nil -} - -// PtySize returns *windows.Coord object -func (w *WinSize) PtySize() *windows.Coord { - return &windows.Coord{ - X: int16(w.X), - Y: int16(w.Y), - } -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go deleted file mode 100644 index f19f5bb4f2..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go +++ /dev/null @@ -1,125 +0,0 @@ -//+build windows - -package dmsgpty - -import ( - "errors" - "fmt" - "os" - "sync" - "syscall" - - "github.com/ActiveState/termtest/conpty" -) - -// Pty errors. -var ( - ErrPtyAlreadyRunning = errors.New("a pty session is already running") - ErrPtyNotRunning = errors.New("no active pty session") -) - -// Pty runs a local pty. -type Pty struct { - pty *conpty.ConPty - mx sync.RWMutex -} - -// NewPty creates a new Pty. -func NewPty() *Pty { - return new(Pty) -} - -// Stop stops the running command and closes the pty. -func (s *Pty) Stop() error { - s.mx.Lock() - defer s.mx.Unlock() - - if s.pty == nil { - return ErrPtyNotRunning - } - - err := s.pty.Close() - s.pty = nil - return err -} - -// Read reads any stdout or stderr outputs from the pty. -func (s *Pty) Read(b []byte) (int, error) { - s.mx.RLock() - defer s.mx.RUnlock() - - if s.pty == nil { - return 0, ErrPtyNotRunning - } - - return s.pty.OutPipe().Read(b) -} - -// Write writes to the stdin of the pty. -func (s *Pty) Write(b []byte) (int, error) { - s.mx.RLock() - defer s.mx.RUnlock() - - if s.pty == nil { - return 0, ErrPtyNotRunning - } - - res, err := s.pty.Write(b) - return int(res), err -} - -// Start runs a command with the given command name, args and optional window size. -func (s *Pty) Start(name string, args []string, size *WinSize) error { - s.mx.Lock() - defer s.mx.Unlock() - - if s.pty != nil { - return ErrPtyAlreadyRunning - } - - var err error - - if size == nil { - size, err = getSize() - if err != nil { - return err - } - - } - fmt.Printf("Size of term: X=>%d, Y=>%d\n", size.X, size.Y) - pty, err := conpty.New( - int16(size.X), int16(size.Y), - ) - if err != nil { - return err - } - - pid, _, err := pty.Spawn( - name, - args, - &syscall.ProcAttr{ - Env: os.Environ(), - }, - ) - - if err != nil { - return err - } - - fmt.Printf("starting process with pid %d \n", pid) - - s.pty = pty - return nil -} - -// SetPtySize sets the pty size. -func (s *Pty) SetPtySize(size *WinSize) error { - s.mx.RLock() - defer s.mx.RUnlock() - - if s.pty == nil { - return ErrPtyNotRunning - } - - return s.pty.Resize(uint16(size.X), uint16(size.Y)) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go index b75d52c434..bf1b5d4a15 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go @@ -10,6 +10,7 @@ import ( "sync/atomic" "time" + "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" "nhooyr.io/websocket" @@ -31,7 +32,7 @@ type UIConfig struct { // DefaultUIConfig returns the default UI config. func DefaultUIConfig() UIConfig { return UIConfig{ - CmdName: DefaultCmd, + CmdName: "/bin/bash", CmdArgs: nil, } } @@ -154,7 +155,7 @@ func (ui *UI) Handler() http.HandlerFunc { } defer func() { log.WithError(ptyC.Close()).Debug("Closed ptyC.") }() - if err = ui.uiStartSize(ptyC); err != nil { + if err := ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, &pty.Winsize{Rows: wsRows, Cols: wsCols}); err != nil { log.Print("xxxx") writeWSError(log, wsConn, err) diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go deleted file mode 100644 index 4047d058b1..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go +++ /dev/null @@ -1,15 +0,0 @@ -//+build !windows - -package dmsgpty - -import ( - "github.com/creack/pty" -) - -func (ui *UI) uiStartSize(ptyC *PtyClient) error { - winSize, err := NewWinSize(&pty.Winsize{Rows: wsRows, Cols: wsCols}) - if err != nil { - return err - } - return ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, winSize) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go deleted file mode 100644 index b8905dc5e6..0000000000 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go +++ /dev/null @@ -1,16 +0,0 @@ -//+build windows - -package dmsgpty - -import "golang.org/x/sys/windows" - -func (ui *UI) uiStartSize(ptyC *PtyClient) error { - ws, err := NewWinSize(&windows.Coord{ - X: wsCols, - Y: wsRows, - }) - if err != nil { - return err - } - return ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, ws) -} diff --git a/vendor/github.com/skycoin/dmsg/entity_common.go b/vendor/github.com/skycoin/dmsg/entity_common.go index afcd01764e..a790b04e6e 100644 --- a/vendor/github.com/skycoin/dmsg/entity_common.go +++ b/vendor/github.com/skycoin/dmsg/entity_common.go @@ -30,8 +30,8 @@ type EntityCommon struct { log logrus.FieldLogger - setSessionCallback func(ctx context.Context) error - delSessionCallback func(ctx context.Context) error + setSessionCallback func(ctx context.Context, sessionCount int) error + delSessionCallback func(ctx context.Context, sessionCount int) error } func (c *EntityCommon) init(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, log logrus.FieldLogger, updateInterval time.Duration) { @@ -107,7 +107,7 @@ func (c *EntityCommon) setSession(ctx context.Context, dSes *SessionCommon) bool c.sessions[dSes.RemotePK()] = dSes if c.setSessionCallback != nil { - if err := c.setSessionCallback(ctx); err != nil { + if err := c.setSessionCallback(ctx, len(c.sessions)); err != nil { c.log. WithField("func", "EntityCommon.setSession"). WithError(err). @@ -121,7 +121,7 @@ func (c *EntityCommon) delSession(ctx context.Context, pk cipher.PubKey) { c.sessionsMx.Lock() delete(c.sessions, pk) if c.delSessionCallback != nil { - if err := c.delSessionCallback(ctx); err != nil { + if err := c.delSessionCallback(ctx, len(c.sessions)); err != nil { c.log. WithField("func", "EntityCommon.delSession"). WithError(err). @@ -250,21 +250,33 @@ func (c *EntityCommon) updateClientEntry(ctx context.Context, done chan struct{} return c.dc.PutEntry(ctx, c.sk, entry) } -func (c *EntityCommon) delClientEntry(ctx context.Context, _ chan struct{}) (err error) { +func (c *EntityCommon) updateClientEntryLoop(ctx context.Context, done chan struct{}) { + t := time.NewTimer(c.updateInterval) + defer t.Stop() - entry, err := c.dc.Entry(ctx, c.pk) - if err != nil { - return err - } + for { + select { + case <-ctx.Done(): + return - defer func() { - if err == nil { - c.log.Debug("Entry Deleted successfully.") - } - }() + case <-t.C: + if lastUpdate, due := c.updateIsDue(); !due { + t.Reset(c.updateInterval - time.Since(lastUpdate)) + continue + } + + c.sessionsMx.Lock() + err := c.updateClientEntry(ctx, done) + c.sessionsMx.Unlock() + + if err != nil { + c.log.WithError(err).Warn("Failed to update discovery entry.") + } - c.log.WithField("entry", entry).Debug("Deleting entry.") - return c.dc.DelEntry(ctx, entry) + // Ensure we trigger another update within given 'updateInterval'. + t.Reset(c.updateInterval) + } + } } func getServerEntry(ctx context.Context, dc disc.APIClient, srvPK cipher.PubKey) (*disc.Entry, error) { diff --git a/vendor/github.com/skycoin/dmsg/go.mod b/vendor/github.com/skycoin/dmsg/go.mod index d762bd66bb..8c834f956c 100644 --- a/vendor/github.com/skycoin/dmsg/go.mod +++ b/vendor/github.com/skycoin/dmsg/go.mod @@ -3,7 +3,6 @@ module github.com/skycoin/dmsg go 1.16 require ( - github.com/ActiveState/termtest/conpty v0.5.0 github.com/VictoriaMetrics/metrics v1.12.3 github.com/creack/pty v1.1.10 github.com/go-chi/chi v4.1.2+incompatible @@ -25,9 +24,9 @@ require ( github.com/skycoin/yamux v0.0.0-20200803175205-571ceb89da9f github.com/spf13/cobra v0.0.5 github.com/stretchr/testify v1.4.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c + golang.org/x/sys v0.0.0-20210112080510-489259a85091 + golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect nhooyr.io/websocket v1.8.2 ) diff --git a/vendor/github.com/skycoin/dmsg/go.sum b/vendor/github.com/skycoin/dmsg/go.sum index a9c78bcebf..ac9db4222f 100644 --- a/vendor/github.com/skycoin/dmsg/go.sum +++ b/vendor/github.com/skycoin/dmsg/go.sum @@ -1,13 +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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I= github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -90,8 +84,6 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pires/go-proxyproto v0.3.3 h1:jOXGrsAfSQVFiD1hWg1aiHpLYsd6SJw/8cLN594sB7Q= github.com/pires/go-proxyproto v0.3.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -151,13 +143,10 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0= golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/skycoin/dmsg/server.go b/vendor/github.com/skycoin/dmsg/server.go index 638d9d118e..7ecc88f84f 100644 --- a/vendor/github.com/skycoin/dmsg/server.go +++ b/vendor/github.com/skycoin/dmsg/server.go @@ -67,10 +67,10 @@ func NewServer(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Serv s.done = make(chan struct{}) s.addrDone = make(chan struct{}) s.maxSessions = conf.MaxSessions - s.setSessionCallback = func(ctx context.Context) error { + s.setSessionCallback = func(ctx context.Context, sessionCount int) error { return s.updateServerEntry(ctx, s.AdvertisedAddr(), s.maxSessions) } - s.delSessionCallback = func(ctx context.Context) error { + s.delSessionCallback = func(ctx context.Context, sessionCount int) error { return s.updateServerEntry(ctx, s.AdvertisedAddr(), s.maxSessions) } return s diff --git a/vendor/modules.txt b/vendor/modules.txt index 134651e835..3a033f2e10 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,11 +1,6 @@ -# github.com/ActiveState/termtest/conpty v0.5.0 -github.com/ActiveState/termtest/conpty # github.com/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51 ## explicit github.com/AudriusButkevicius/pfilter -# github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 -github.com/Azure/go-ansiterm -github.com/Azure/go-ansiterm/winterm # github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d ## explicit github.com/StackExchange/wmi @@ -133,7 +128,7 @@ github.com/shirou/gopsutil/process ## explicit github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/syslog -# github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 => ../dmsg +# github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 ## explicit github.com/skycoin/dmsg github.com/skycoin/dmsg/buildinfo @@ -293,4 +288,3 @@ nhooyr.io/websocket/internal/bpool nhooyr.io/websocket/internal/errd nhooyr.io/websocket/internal/wsjs nhooyr.io/websocket/internal/xsync -# github.com/skycoin/dmsg => ../dmsg From 1467386451dfa3a0cebb7d9743551252dd38b837 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 19:27:17 +0530 Subject: [PATCH 04/13] Remove dmsg server from NewTransportListener --- pkg/transport/setup/visor.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/transport/setup/visor.go b/pkg/transport/setup/visor.go index 947ae9ce65..f57d3a7187 100644 --- a/pkg/transport/setup/visor.go +++ b/pkg/transport/setup/visor.go @@ -27,8 +27,6 @@ func NewTransportListener(ctx context.Context, conf *visorconfig.V1, dmsgC *dmsg log := masterLogger.PackageLogger("transport_setup") log.WithField("local_pk", conf.PK).Info("Connecting to the dmsg network.") - go dmsgC.Serve(ctx) - select { case <-dmsgC.Ready(): log.WithField("local_pk", conf.PK).Info("Connected!") From 62b0e13e0c91081d63b766391524b954d224cdf5 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 19:37:42 +0530 Subject: [PATCH 05/13] Add dmsg closing log to TransportListener --- pkg/transport/setup/visor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/transport/setup/visor.go b/pkg/transport/setup/visor.go index f57d3a7187..6e61f3ae69 100644 --- a/pkg/transport/setup/visor.go +++ b/pkg/transport/setup/visor.go @@ -60,7 +60,12 @@ func (ts *TransportListener) Serve(ctx context.Context) { for { conn, err := lis.AcceptStream() if err != nil { - ts.log.WithError(err).Error("failed to accept") + log := ts.log.WithError(err) + if err == dmsg.ErrEntityClosed { + log.Info("Dmsg client stopped serving.") + } else { + log.Error("Failed to accept") + } break } remotePK := conn.RawRemoteAddr().PK From 2639c76e3e75a97e7d846c2a7157478a18f03dd2 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 19:40:26 +0530 Subject: [PATCH 06/13] Add dmsg closed log to serveDmsg in hypervisor --- pkg/visor/hypervisor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/visor/hypervisor.go b/pkg/visor/hypervisor.go index 03320cf629..a2943f4a36 100644 --- a/pkg/visor/hypervisor.go +++ b/pkg/visor/hypervisor.go @@ -1549,7 +1549,12 @@ func (hv *Hypervisor) serveDmsg(ctx context.Context, log *logging.Logger) { go func() { <-hv.dmsgC.Ready() if err := hv.ServeRPC(ctx, hv.c.DmsgPort); err != nil { - log.WithError(err).Fatal("Failed to serve RPC client over dmsg.") + log := log.WithError(err) + if err == dmsg.ErrEntityClosed { + log.Info("Dmsg client stopped serving.") + } else { + log.Error("Failed to serve RPC client over dmsg.") + } } }() log.WithField("addr", dmsg.Addr{PK: hv.c.PK, Port: hv.c.DmsgPort}). From 171be17acad6d741203317a9a1eb357692333b91 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 19:42:57 +0530 Subject: [PATCH 07/13] Added dmsg close log --- pkg/transport/manager.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/transport/manager.go b/pkg/transport/manager.go index 3369ccee4f..f383deab04 100644 --- a/pkg/transport/manager.go +++ b/pkg/transport/manager.go @@ -203,7 +203,12 @@ func (tm *Manager) acceptTransports(ctx context.Context, lis network.Listener, t return default: if err := tm.acceptTransport(ctx, lis); err != nil { - tm.Logger.Warnf("Failed to accept transport: %v", err) + log := tm.Logger.WithError(err) + if err == dmsg.ErrEntityClosed { + log.Info("Dmsg client stopped serving.") + } else { + log.Warnf("Failed to accept transport") + } if errors.Is(err, io.ErrClosedPipe) { return } From 10d4c97c6c3907ad8957277cbcfb064adcde2752 Mon Sep 17 00:00:00 2001 From: ersonp Date: Fri, 10 Sep 2021 19:47:28 +0530 Subject: [PATCH 08/13] Requested changes and removed extra go routine --- pkg/visor/init.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/visor/init.go b/pkg/visor/init.go index 4255d5504b..cedb4b28d0 100644 --- a/pkg/visor/init.go +++ b/pkg/visor/init.go @@ -216,9 +216,7 @@ func initDmsg(ctx context.Context, v *Visor, log *logging.Logger) error { wg.Add(1) go func() { defer wg.Done() - time.Sleep(200 * time.Millisecond) - go dmsgC.Serve(context.Background()) - time.Sleep(200 * time.Millisecond) + dmsgC.Serve(context.Background()) }() v.pushCloseStack("dmsg", func() error { From 4aaa3c9a0ceb6f9e41dcb0f59085893608de3921 Mon Sep 17 00:00:00 2001 From: ersonp Date: Tue, 14 Sep 2021 21:08:43 +0530 Subject: [PATCH 09/13] Update code --- pkg/router/router.go | 4 ++-- pkg/transport/manager.go | 7 ++++--- pkg/transport/setup/visor.go | 4 ++-- pkg/visor/hypervisor.go | 5 +++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pkg/router/router.go b/pkg/router/router.go index 9792414b3c..0a6d52af3f 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -351,9 +351,9 @@ func (r *router) serveSetup() { log := r.logger.WithError(err) if err == dmsg.ErrEntityClosed { log.Info("Setup client stopped serving.") - } else { - log.Error("Setup client stopped serving due to unexpected error.") + return } + log.Error("Setup client stopped serving due to unexpected error.") return } diff --git a/pkg/transport/manager.go b/pkg/transport/manager.go index f383deab04..2979948f38 100644 --- a/pkg/transport/manager.go +++ b/pkg/transport/manager.go @@ -204,14 +204,15 @@ func (tm *Manager) acceptTransports(ctx context.Context, lis network.Listener, t default: if err := tm.acceptTransport(ctx, lis); err != nil { log := tm.Logger.WithError(err) - if err == dmsg.ErrEntityClosed { + if errors.Is(err, dmsg.ErrEntityClosed) { log.Info("Dmsg client stopped serving.") - } else { - log.Warnf("Failed to accept transport") + return } if errors.Is(err, io.ErrClosedPipe) { return } + log.Warnf("Failed to accept transport") + return } } } diff --git a/pkg/transport/setup/visor.go b/pkg/transport/setup/visor.go index 6e61f3ae69..d62f0e1f94 100644 --- a/pkg/transport/setup/visor.go +++ b/pkg/transport/setup/visor.go @@ -63,9 +63,9 @@ func (ts *TransportListener) Serve(ctx context.Context) { log := ts.log.WithError(err) if err == dmsg.ErrEntityClosed { log.Info("Dmsg client stopped serving.") - } else { - log.Error("Failed to accept") + break } + log.Error("Failed to accept") break } remotePK := conn.RawRemoteAddr().PK diff --git a/pkg/visor/hypervisor.go b/pkg/visor/hypervisor.go index a2943f4a36..dc7247a525 100644 --- a/pkg/visor/hypervisor.go +++ b/pkg/visor/hypervisor.go @@ -1552,9 +1552,10 @@ func (hv *Hypervisor) serveDmsg(ctx context.Context, log *logging.Logger) { log := log.WithError(err) if err == dmsg.ErrEntityClosed { log.Info("Dmsg client stopped serving.") - } else { - log.Error("Failed to serve RPC client over dmsg.") + return } + log.Error("Failed to serve RPC client over dmsg.") + return } }() log.WithField("addr", dmsg.Addr{PK: hv.c.PK, Port: hv.c.DmsgPort}). From 1faca30d98a589e4587953c38c0b54fa3052c36a Mon Sep 17 00:00:00 2001 From: ersonp Date: Wed, 15 Sep 2021 00:15:45 +0530 Subject: [PATCH 10/13] Requested changes --- pkg/router/router.go | 2 +- pkg/transport/setup/visor.go | 3 ++- pkg/visor/hypervisor.go | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/router/router.go b/pkg/router/router.go index 0a6d52af3f..cb0cfe9390 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -349,7 +349,7 @@ func (r *router) serveSetup() { conn, err := r.sl.AcceptStream() if err != nil { log := r.logger.WithError(err) - if err == dmsg.ErrEntityClosed { + if errors.Is(err, dmsg.ErrEntityClosed) { log.Info("Setup client stopped serving.") return } diff --git a/pkg/transport/setup/visor.go b/pkg/transport/setup/visor.go index d62f0e1f94..78b3cad478 100644 --- a/pkg/transport/setup/visor.go +++ b/pkg/transport/setup/visor.go @@ -2,6 +2,7 @@ package setup import ( "context" + "errors" "fmt" "net/rpc" @@ -61,7 +62,7 @@ func (ts *TransportListener) Serve(ctx context.Context) { conn, err := lis.AcceptStream() if err != nil { log := ts.log.WithError(err) - if err == dmsg.ErrEntityClosed { + if errors.Is(err, dmsg.ErrEntityClosed) { log.Info("Dmsg client stopped serving.") break } diff --git a/pkg/visor/hypervisor.go b/pkg/visor/hypervisor.go index dc7247a525..f3d9bbd734 100644 --- a/pkg/visor/hypervisor.go +++ b/pkg/visor/hypervisor.go @@ -1550,7 +1550,7 @@ func (hv *Hypervisor) serveDmsg(ctx context.Context, log *logging.Logger) { <-hv.dmsgC.Ready() if err := hv.ServeRPC(ctx, hv.c.DmsgPort); err != nil { log := log.WithError(err) - if err == dmsg.ErrEntityClosed { + if errors.Is(err, dmsg.ErrEntityClosed) { log.Info("Dmsg client stopped serving.") return } From caa061dd9f65566e7c54559c3b8834641759b840 Mon Sep 17 00:00:00 2001 From: ersonp Date: Thu, 16 Sep 2021 14:36:40 +0530 Subject: [PATCH 11/13] Update dmsg --- go.mod | 2 +- go.sum | 8 + .../ActiveState/termtest/conpty/LICENSE | 29 + .../ActiveState/termtest/conpty/README.md | 23 + .../termtest/conpty/conpty_windows.go | 250 ++++++ .../ActiveState/termtest/conpty/doc.go | 11 + .../termtest/conpty/exec_windows.go | 161 ++++ .../ActiveState/termtest/conpty/go.mod | 8 + .../ActiveState/termtest/conpty/go.sum | 4 + .../termtest/conpty/syscall_windows.go | 112 +++ .../ActiveState/termtest/conpty/term_other.go | 7 + .../termtest/conpty/term_windows.go | 61 ++ vendor/github.com/Azure/go-ansiterm/LICENSE | 21 + vendor/github.com/Azure/go-ansiterm/README.md | 12 + .../github.com/Azure/go-ansiterm/constants.go | 188 +++++ .../github.com/Azure/go-ansiterm/context.go | 7 + .../Azure/go-ansiterm/csi_entry_state.go | 49 ++ .../Azure/go-ansiterm/csi_param_state.go | 38 + .../go-ansiterm/escape_intermediate_state.go | 36 + .../Azure/go-ansiterm/escape_state.go | 47 ++ .../Azure/go-ansiterm/event_handler.go | 90 +++ .../Azure/go-ansiterm/ground_state.go | 24 + .../Azure/go-ansiterm/osc_string_state.go | 31 + vendor/github.com/Azure/go-ansiterm/parser.go | 151 ++++ .../go-ansiterm/parser_action_helpers.go | 99 +++ .../Azure/go-ansiterm/parser_actions.go | 119 +++ vendor/github.com/Azure/go-ansiterm/states.go | 71 ++ .../github.com/Azure/go-ansiterm/utilities.go | 21 + .../Azure/go-ansiterm/winterm/ansi.go | 182 +++++ .../Azure/go-ansiterm/winterm/api.go | 327 ++++++++ .../go-ansiterm/winterm/attr_translation.go | 100 +++ .../go-ansiterm/winterm/cursor_helpers.go | 101 +++ .../go-ansiterm/winterm/erase_helpers.go | 84 ++ .../go-ansiterm/winterm/scroll_helper.go | 118 +++ .../Azure/go-ansiterm/winterm/utilities.go | 9 + .../go-ansiterm/winterm/win_event_handler.go | 743 ++++++++++++++++++ vendor/github.com/skycoin/dmsg/.gitignore | 1 + vendor/github.com/skycoin/dmsg/Makefile | 33 +- vendor/github.com/skycoin/dmsg/client.go | 17 +- .../skycoin/dmsg/cmdutil/service_flags.go | 2 - .../skycoin/dmsg/cmdutil/signal_context.go | 2 +- vendor/github.com/skycoin/dmsg/disc/client.go | 57 +- .../skycoin/dmsg/disc/http_message.go | 1 + .../github.com/skycoin/dmsg/disc/testing.go | 12 + vendor/github.com/skycoin/dmsg/dmsgpty/cli.go | 53 +- .../skycoin/dmsg/dmsgpty/cli_unix.go | 63 ++ .../skycoin/dmsg/dmsgpty/cli_windows.go | 44 ++ .../github.com/skycoin/dmsg/dmsgpty/conf.go | 52 +- .../github.com/skycoin/dmsg/dmsgpty/const.go | 12 - .../skycoin/dmsg/dmsgpty/const_unix.go | 24 + .../skycoin/dmsg/dmsgpty/const_windows.go | 27 + .../github.com/skycoin/dmsg/dmsgpty/host.go | 10 +- .../skycoin/dmsg/dmsgpty/pty_client.go | 41 +- .../dmsg/dmsgpty/pty_client_windows.go | 31 + .../skycoin/dmsg/dmsgpty/pty_gateway.go | 48 +- .../skycoin/dmsg/dmsgpty/pty_gateway_unix.go | 32 + .../dmsg/dmsgpty/pty_gateway_windows.go | 28 + .../dmsg/dmsgpty/{pty.go => pty_unix.go} | 58 +- .../skycoin/dmsg/dmsgpty/pty_windows.go | 125 +++ vendor/github.com/skycoin/dmsg/dmsgpty/ui.go | 5 +- .../skycoin/dmsg/dmsgpty/ui_unix.go | 15 + .../skycoin/dmsg/dmsgpty/ui_windows.go | 16 + .../github.com/skycoin/dmsg/entity_common.go | 52 +- vendor/github.com/skycoin/dmsg/go.mod | 6 +- vendor/github.com/skycoin/dmsg/go.sum | 11 + vendor/github.com/skycoin/dmsg/server.go | 4 +- vendor/modules.txt | 7 +- 67 files changed, 4031 insertions(+), 202 deletions(-) create mode 100644 vendor/github.com/ActiveState/termtest/conpty/LICENSE create mode 100644 vendor/github.com/ActiveState/termtest/conpty/README.md create mode 100644 vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/doc.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/exec_windows.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/go.mod create mode 100644 vendor/github.com/ActiveState/termtest/conpty/go.sum create mode 100644 vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/term_other.go create mode 100644 vendor/github.com/ActiveState/termtest/conpty/term_windows.go create mode 100644 vendor/github.com/Azure/go-ansiterm/LICENSE create mode 100644 vendor/github.com/Azure/go-ansiterm/README.md create mode 100644 vendor/github.com/Azure/go-ansiterm/constants.go create mode 100644 vendor/github.com/Azure/go-ansiterm/context.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_entry_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/csi_param_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/escape_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/event_handler.go create mode 100644 vendor/github.com/Azure/go-ansiterm/ground_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/osc_string_state.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_actions.go create mode 100644 vendor/github.com/Azure/go-ansiterm/states.go create mode 100644 vendor/github.com/Azure/go-ansiterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/ansi.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/api.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/utilities.go create mode 100644 vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go rename vendor/github.com/skycoin/dmsg/dmsgpty/{pty.go => pty_unix.go} (80%) create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go create mode 100644 vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go diff --git a/go.mod b/go.mod index f2953ba5bb..27b2ab37fd 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/schollz/progressbar/v2 v2.15.0 github.com/shirou/gopsutil v2.20.5+incompatible github.com/sirupsen/logrus v1.8.1 - github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 + github.com/skycoin/dmsg v0.0.0-20210915195912-2f9b055f39fe github.com/skycoin/skycoin v0.27.1 github.com/skycoin/yamux v0.0.0-20200803175205-571ceb89da9f github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 diff --git a/go.sum b/go.sum index ab807602ba..292b9b40bf 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,12 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +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/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51 h1:77WF6PJZQiA3OMt8Nl+PH/dbkszumosxunW36ZQj2QQ= github.com/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51/go.mod h1:EEEtt5r8y0gGHlRFF2+cLx0WUy/rKHnjALmom5E0+74= +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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= @@ -281,6 +285,8 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 h1:Dlf/sDocfSgjP+ipVxzOtDVkkLN1u6ZqUyXzp22AkU4= github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2/go.mod h1:XguFKwECpSMq+/AKv8TCTsRlCEHSEIbqoaxOyceK2Ys= +github.com/skycoin/dmsg v0.0.0-20210915195912-2f9b055f39fe h1:3mNjtnypa8DC4kNiuLOJ1mqMdXPIAI6Se4k8fNNU2P0= +github.com/skycoin/dmsg v0.0.0-20210915195912-2f9b055f39fe/go.mod h1:qs+tELY7/gHRHqCK0iPp62BuYlu10OcV5zN0lpa1Scc= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6 h1:1Nc5EBY6pjfw1kwW0duwyG+7WliWz5u9kgk1h5MnLuA= github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:UXghlricA7J3aRD/k7p/zBObQfmBawwCxIVPVjz2Q3o= github.com/skycoin/skycoin v0.26.0/go.mod h1:78nHjQzd8KG0jJJVL/j0xMmrihXi70ti63fh8vXScJw= @@ -434,11 +440,13 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= diff --git a/vendor/github.com/ActiveState/termtest/conpty/LICENSE b/vendor/github.com/ActiveState/termtest/conpty/LICENSE new file mode 100644 index 0000000000..0ea09c8e0d --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, ActiveState Software +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/ActiveState/termtest/conpty/README.md b/vendor/github.com/ActiveState/termtest/conpty/README.md new file mode 100644 index 0000000000..fb093f8559 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/README.md @@ -0,0 +1,23 @@ +# termtest/conpty + +Support for the [Windows pseudo +console](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/) +in Go. + +Developed as part of the cross-platform terminal automation library +[expect](https://github.com/ActiveState/termtest/expect) for the [ActiveState +state tool](https://www.activestate.com/products/platform/state-tool/). + +## Example + +See ./cmd/example/main.go + +## Client configuration + +On Windows, you may have to adjust the programme that you are running in the +pseudo-console, by configuring the standard output handler to process virtual +terminal codes. See https://docs.microsoft.com/en-us/windows/console/setconsolemode + +This package comes with a convenience function `InitTerminal()` that you can +use in your client to set this option. + diff --git a/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go b/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go new file mode 100644 index 0000000000..e0a1821fc9 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/conpty_windows.go @@ -0,0 +1,250 @@ +// Copyright 2020 ActiveState Software. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package conpty + +import ( + "fmt" + "log" + "os" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +// ConPty represents a windows pseudo console. +// Attach a process to it by calling the Spawn() method. +// You can send UTF encoded commands to it with Write() and listen to +// its output stream by accessing the output pipe via OutPipe() +type ConPty struct { + hpCon *windows.Handle + pipeFdIn windows.Handle + pipeFdOut windows.Handle + startupInfo startupInfoEx + consoleSize uintptr + inPipe *os.File + outPipe *os.File + attributeListBuffer []byte +} + +// New returns a new ConPty pseudo terminal device +func New(columns int16, rows int16) (c *ConPty, err error) { + c = &ConPty{ + hpCon: new(windows.Handle), + startupInfo: startupInfoEx{}, + consoleSize: uintptr(columns) + (uintptr(rows) << 16), + } + err = c.createPseudoConsoleAndPipes() + if err != nil { + return nil, err + } + err = c.initializeStartupInfoAttachedToPTY() + if err != nil { + return nil, err + } + return +} + +// Close closes the pseudo-terminal and cleans up all attached resources +func (c *ConPty) Close() (err error) { + err = deleteProcThreadAttributeList(c.startupInfo.lpAttributeList) + if err != nil { + log.Printf("Failed to free delete proc thread attribute list: %v", err) + } + /* + _, err = windows.LocalFree(c.startupInfo.lpAttributeList) + if err != nil { + log.Printf("Failed to free the lpAttributeList") + } + */ + err = closePseudoConsole(*c.hpCon) + if err != nil { + log.Printf("Failed to close pseudo console: %v", err) + } + c.inPipe.Close() + c.outPipe.Close() + return +} + +// OutPipe returns the output pipe of the pseudo terminal +func (c *ConPty) OutPipe() *os.File { + return c.outPipe +} + +// InPipe returns input pipe of the pseudo terminal +// Note: It is safer to use the Write method to prevent partially-written VT sequences +// from corrupting the terminal +func (c *ConPty) InPipe() *os.File { + return c.inPipe +} + +func (c *ConPty) OutFd() uintptr { + return c.outPipe.Fd() +} + +// Write safely writes bytes to the pseudo terminal +func (c *ConPty) Write(buf []byte) (uint32, error) { + var n uint32 + err := windows.WriteFile(c.pipeFdIn, buf, &n, nil) + return n, err +} + +var zeroProcAttr syscall.ProcAttr + +// Spawn spawns a new process attached to the pseudo terminal +func (c *ConPty) Spawn(argv0 string, argv []string, attr *syscall.ProcAttr) (pid int, handle uintptr, err error) { + + if attr == nil { + attr = &zeroProcAttr + } + + if attr.Sys != nil { + log.Printf("Warning: SysProc attributes are not supported by Spawn.") + } + + if len(attr.Files) != 0 { + log.Printf("Warning: Ignoring 'Files' attribute in ProcAttr argument.") + } + + if len(attr.Dir) != 0 { + // StartProcess assumes that argv0 is relative to attr.Dir, + // because it implies Chdir(attr.Dir) before executing argv0. + // Windows CreateProcess assumes the opposite: it looks for + // argv0 relative to the current directory, and, only once the new + // process is started, it does Chdir(attr.Dir). We are adjusting + // for that difference here by making argv0 absolute. + var err error + argv0, err = joinExeDirAndFName(attr.Dir, argv0) + if err != nil { + return 0, 0, err + } + } + argv0p, err := windows.UTF16PtrFromString(argv0) + if err != nil { + return 0, 0, err + } + + // Windows CreateProcess takes the command line as a single string: + // use attr.CmdLine if set, else build the command line by escaping + // and joining each argument with spaces + cmdline := makeCmdLine(argv) + + var argvp *uint16 + if len(cmdline) != 0 { + argvp, err = windows.UTF16PtrFromString(cmdline) + if err != nil { + return 0, 0, err + } + } + + var dirp *uint16 + if len(attr.Dir) != 0 { + dirp, err = windows.UTF16PtrFromString(attr.Dir) + if err != nil { + return 0, 0, err + } + } + + c.startupInfo.startupInfo.Flags = windows.STARTF_USESTDHANDLES + + pi := new(windows.ProcessInformation) + + flags := uint32(windows.CREATE_UNICODE_ENVIRONMENT) | extendedStartupinfoPresent + + var zeroSec windows.SecurityAttributes + pSec := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(zeroSec)), InheritHandle: 1} + tSec := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(zeroSec)), InheritHandle: 1} + + // c.startupInfo.startupInfo.Cb = uint32(unsafe.Sizeof(c.startupInfo)) + err = windows.CreateProcess( + argv0p, + argvp, + pSec, // process handle not inheritable + tSec, // thread handles not inheritable, + false, + flags, + createEnvBlock(addCriticalEnv(dedupEnvCase(true, attr.Env))), + dirp, // use current directory later: dirp, + &c.startupInfo.startupInfo, + pi) + + if err != nil { + return 0, 0, err + } + defer windows.CloseHandle(windows.Handle(pi.Thread)) + + return int(pi.ProcessId), uintptr(pi.Process), nil +} + +func (c *ConPty) createPseudoConsoleAndPipes() (err error) { + var hPipePTYIn windows.Handle + var hPipePTYOut windows.Handle + + if err := windows.CreatePipe(&hPipePTYIn, &c.pipeFdIn, nil, 0); err != nil { + log.Fatalf("Failed to create PTY input pipe: %v", err) + } + if err := windows.CreatePipe(&c.pipeFdOut, &hPipePTYOut, nil, 0); err != nil { + log.Fatalf("Failed to create PTY output pipe: %v", err) + } + + err = createPseudoConsole(c.consoleSize, hPipePTYIn, hPipePTYOut, c.hpCon) + if err != nil { + return fmt.Errorf("failed to create pseudo console: %d, %v", uintptr(*c.hpCon), err) + } + + // Note: We can close the handles to the PTY-end of the pipes here + // because the handles are dup'ed into the ConHost and will be released + // when the ConPTY is destroyed. + if hPipePTYOut != windows.InvalidHandle { + windows.CloseHandle(hPipePTYOut) + } + if hPipePTYIn != windows.InvalidHandle { + windows.CloseHandle(hPipePTYIn) + } + + c.inPipe = os.NewFile(uintptr(c.pipeFdIn), "|0") + c.outPipe = os.NewFile(uintptr(c.pipeFdOut), "|1") + + return +} + +func (c *ConPty) Resize(cols uint16, rows uint16) error { + return resizePseudoConsole(*c.hpCon, uintptr(cols)+(uintptr(rows)<<16)) +} + +func (c *ConPty) initializeStartupInfoAttachedToPTY() (err error) { + + var attrListSize uint64 + c.startupInfo.startupInfo.Cb = uint32(unsafe.Sizeof(c.startupInfo)) + + err = initializeProcThreadAttributeList(0, 1, &attrListSize) + if err != nil { + return fmt.Errorf("could not retrieve list size: %v", err) + } + + c.attributeListBuffer = make([]byte, attrListSize) + // c.startupInfo.lpAttributeList, err = localAlloc(attrListSize) + // if err != nil { + // return fmt.Errorf("Could not allocate local memory: %v", err) + // } + + c.startupInfo.lpAttributeList = windows.Handle(unsafe.Pointer(&c.attributeListBuffer[0])) + + err = initializeProcThreadAttributeList(uintptr(c.startupInfo.lpAttributeList), 1, &attrListSize) + if err != nil { + return fmt.Errorf("failed to initialize proc thread attributes for conpty: %v", err) + } + + err = updateProcThreadAttributeList( + c.startupInfo.lpAttributeList, + procThreadAttributePseudoconsole, + *c.hpCon, + unsafe.Sizeof(*c.hpCon)) + if err != nil { + return fmt.Errorf("failed to update proc thread attributes attributes for conpty usage: %v", err) + } + + return +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/doc.go b/vendor/github.com/ActiveState/termtest/conpty/doc.go new file mode 100644 index 0000000000..b423fb62cc --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/doc.go @@ -0,0 +1,11 @@ +// Copyright 2020 ActiveState Software. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +// Package conpty provides functions for creating a process attached to a +// ConPTY pseudo-terminal. This allows the process to call console specific +// API functions without an actual terminal being present. +// +// The concept is best explained in this blog post: +// https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ +package conpty diff --git a/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go b/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go new file mode 100644 index 0000000000..6d0777054d --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/exec_windows.go @@ -0,0 +1,161 @@ +// Copyright 2009 The Go Authors. All rights reserved. + +// This file has copies of unexported functions form the go source code, +// hence the above copyright message + +package conpty + +import ( + "os" + "strings" + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +// makeCmdLine builds a command line out of args by escaping "special" +// characters and joining the arguments with spaces. +func makeCmdLine(args []string) string { + var s string + for _, v := range args { + if s != "" { + s += " " + } + s += windows.EscapeArg(v) + } + return s +} + +func isSlash(c uint8) bool { + return c == '\\' || c == '/' +} + +func normalizeDir(dir string) (name string, err error) { + ndir, err := syscall.FullPath(dir) + if err != nil { + return "", err + } + if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) { + // dir cannot have \\server\share\path form + return "", syscall.EINVAL + } + return ndir, nil +} + +func volToUpper(ch int) int { + if 'a' <= ch && ch <= 'z' { + ch += 'A' - 'a' + } + return ch +} + +func joinExeDirAndFName(dir, p string) (name string, err error) { + if len(p) == 0 { + return "", syscall.EINVAL + } + if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) { + // \\server\share\path form + return p, nil + } + if len(p) > 1 && p[1] == ':' { + // has drive letter + if len(p) == 2 { + return "", syscall.EINVAL + } + if isSlash(p[2]) { + return p, nil + } else { + d, err := normalizeDir(dir) + if err != nil { + return "", err + } + if volToUpper(int(p[0])) == volToUpper(int(d[0])) { + return syscall.FullPath(d + "\\" + p[2:]) + } else { + return syscall.FullPath(p) + } + } + } else { + // no drive letter + d, err := normalizeDir(dir) + if err != nil { + return "", err + } + if isSlash(p[0]) { + return windows.FullPath(d[:2] + p) + } else { + return windows.FullPath(d + "\\" + p) + } + } +} + +// createEnvBlock converts an array of environment strings into +// the representation required by CreateProcess: a sequence of NUL +// terminated strings followed by a nil. +// Last bytes are two UCS-2 NULs, or four NUL bytes. +func createEnvBlock(envv []string) *uint16 { + if len(envv) == 0 { + return &utf16.Encode([]rune("\x00\x00"))[0] + } + length := 0 + for _, s := range envv { + length += len(s) + 1 + } + length += 1 + + b := make([]byte, length) + i := 0 + for _, s := range envv { + l := len(s) + copy(b[i:i+l], []byte(s)) + copy(b[i+l:i+l+1], []byte{0}) + i = i + l + 1 + } + copy(b[i:i+1], []byte{0}) + + return &utf16.Encode([]rune(string(b)))[0] +} + +// dedupEnvCase is dedupEnv with a case option for testing. +// If caseInsensitive is true, the case of keys is ignored. +func dedupEnvCase(caseInsensitive bool, env []string) []string { + out := make([]string, 0, len(env)) + saw := make(map[string]int, len(env)) // key => index into out + for _, kv := range env { + eq := strings.Index(kv, "=") + if eq < 0 { + out = append(out, kv) + continue + } + k := kv[:eq] + if caseInsensitive { + k = strings.ToLower(k) + } + if dupIdx, isDup := saw[k]; isDup { + out[dupIdx] = kv + continue + } + saw[k] = len(out) + out = append(out, kv) + } + return out +} + +// addCriticalEnv adds any critical environment variables that are required +// (or at least almost always required) on the operating system. +// Currently this is only used for Windows. +func addCriticalEnv(env []string) []string { + for _, kv := range env { + eq := strings.Index(kv, "=") + if eq < 0 { + continue + } + k := kv[:eq] + if strings.EqualFold(k, "SYSTEMROOT") { + // We already have it. + return env + } + } + return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/go.mod b/vendor/github.com/ActiveState/termtest/conpty/go.mod new file mode 100644 index 0000000000..67bb0a5f81 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/go.mod @@ -0,0 +1,8 @@ +module github.com/ActiveState/termtest/conpty + +go 1.12 + +require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 + golang.org/x/sys v0.0.0-20200428200454-593003d681fa +) diff --git a/vendor/github.com/ActiveState/termtest/conpty/go.sum b/vendor/github.com/ActiveState/termtest/conpty/go.sum new file mode 100644 index 0000000000..c1c7bf67bf --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/go.sum @@ -0,0 +1,4 @@ +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= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go b/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go new file mode 100644 index 0000000000..375043114f --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/syscall_windows.go @@ -0,0 +1,112 @@ +// Copyright 2020 ActiveState Software. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file + +package conpty + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +// load some windows system procedures + +var ( + kernel32 = windows.NewLazySystemDLL("kernel32.dll") + procResizePseudoConsole = kernel32.NewProc("ResizePseudoConsole") + procCreatePseudoConsole = kernel32.NewProc("CreatePseudoConsole") + procClosePseudoConsole = kernel32.NewProc("ClosePseudoConsole") + procInitializeProcThreadAttributeList = kernel32.NewProc("InitializeProcThreadAttributeList") + procUpdateProcThreadAttribute = kernel32.NewProc("UpdateProcThreadAttribute") + procLocalAlloc = kernel32.NewProc("LocalAlloc") + procDeleteProcThreadAttributeList = kernel32.NewProc("DeleteProcThreadAttributeList") + procCreateProcessW = kernel32.NewProc("CreateProcessW") +) + +// an extended version of a process startup info, the attribute list points +// to a pseudo terminal object +type startupInfoEx struct { + startupInfo windows.StartupInfo + lpAttributeList windows.Handle +} + +// constant used in CreateProcessW indicating that extended startup info is present +const extendedStartupinfoPresent uint32 = 0x00080000 + +type procThreadAttribute uintptr + +// windows constant needed during initialization of extended startupinfo +const procThreadAttributePseudoconsole procThreadAttribute = 22 | 0x00020000 // this is the only one we support right now + +func initializeProcThreadAttributeList(attributeList uintptr, attributeCount uint32, listSize *uint64) (err error) { + + if attributeList == 0 { + procInitializeProcThreadAttributeList.Call(0, uintptr(attributeCount), 0, uintptr(unsafe.Pointer(listSize))) + return + } + r1, _, e1 := procInitializeProcThreadAttributeList.Call(attributeList, uintptr(attributeCount), 0, uintptr(unsafe.Pointer(listSize))) + + if r1 == 0 { // boolean FALSE + err = e1 + } + + return +} + +func updateProcThreadAttributeList(attributeList windows.Handle, attribute procThreadAttribute, lpValue windows.Handle, lpSize uintptr) (err error) { + + r1, _, e1 := procUpdateProcThreadAttribute.Call(uintptr(attributeList), 0, uintptr(attribute), uintptr(lpValue), lpSize, 0, 0) + + if r1 == 0 { // boolean FALSE + err = e1 + } + + return +} +func deleteProcThreadAttributeList(handle windows.Handle) (err error) { + r1, _, e1 := procDeleteProcThreadAttributeList.Call(uintptr(handle)) + + if r1 == 0 { // boolean FALSE + err = e1 + } + + return +} + +func localAlloc(size uint64) (ptr windows.Handle, err error) { + r1, _, e1 := procLocalAlloc.Call(uintptr(0x0040), uintptr(size)) + if r1 == 0 { + err = e1 + ptr = windows.InvalidHandle + return + } + ptr = windows.Handle(r1) + return +} + +func createPseudoConsole(consoleSize uintptr, ptyIn windows.Handle, ptyOut windows.Handle, hpCon *windows.Handle) (err error) { + r1, _, e1 := procCreatePseudoConsole.Call(consoleSize, uintptr(ptyIn), uintptr(ptyOut), 0, uintptr(unsafe.Pointer(hpCon))) + + if r1 != 0 { // !S_OK + err = e1 + } + return +} + +func resizePseudoConsole(handle windows.Handle, consoleSize uintptr) (err error) { + r1, _, e1 := procResizePseudoConsole.Call(uintptr(handle), consoleSize) + if r1 != 0 { // !S_OK + err = e1 + } + return +} + +func closePseudoConsole(handle windows.Handle) (err error) { + r1, _, e1 := procClosePseudoConsole.Call(uintptr(handle)) + if r1 == 0 { + err = e1 + } + + return +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/term_other.go b/vendor/github.com/ActiveState/termtest/conpty/term_other.go new file mode 100644 index 0000000000..daef1c0792 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/term_other.go @@ -0,0 +1,7 @@ +// +build !windows + +package conpty + +func InitTerminal(_ bool) (func(), error) { + return func() {}, nil +} diff --git a/vendor/github.com/ActiveState/termtest/conpty/term_windows.go b/vendor/github.com/ActiveState/termtest/conpty/term_windows.go new file mode 100644 index 0000000000..df091b5bb6 --- /dev/null +++ b/vendor/github.com/ActiveState/termtest/conpty/term_windows.go @@ -0,0 +1,61 @@ +// +build windows + +package conpty + +import ( + "fmt" + "log" + "syscall" + + "github.com/Azure/go-ansiterm/winterm" +) + +func InitTerminal(disableNewlineAutoReturn bool) (func(), error) { + stdoutFd := int(syscall.Stdout) + + // fmt.Printf("file descriptors <%d >%d\n", stdinFd, stdoutFd) + + oldOutMode, err := winterm.GetConsoleMode(uintptr(stdoutFd)) + if err != nil { + return func() {}, fmt.Errorf("failed to retrieve stdout mode: %w", err) + } + + // fmt.Printf("old modes: <%d >%d\n", oldInMode, oldOutMode) + newOutMode := oldOutMode | winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING + if disableNewlineAutoReturn { + newOutMode |= winterm.DISABLE_NEWLINE_AUTO_RETURN + } + + err = winterm.SetConsoleMode(uintptr(stdoutFd), newOutMode) + if err != nil { + return func() {}, fmt.Errorf("failed to set stdout mode: %w", err) + } + + // dump(uintptr(stdoutFd)) + return func() { + err = winterm.SetConsoleMode(uintptr(stdoutFd), oldOutMode) + if err != nil { + log.Fatalf("Failed to reset output terminal mode to %d: %v\n", oldOutMode, err) + } + }, nil +} + +func dump(fd uintptr) { + fmt.Printf("FD=%d\n", fd) + modes, err := winterm.GetConsoleMode(fd) + if err != nil { + panic(err) + } + + fmt.Printf("ENABLE_ECHO_INPUT=%d, ENABLE_PROCESSED_INPUT=%d ENABLE_LINE_INPUT=%d\n", + modes&winterm.ENABLE_ECHO_INPUT, + modes&winterm.ENABLE_PROCESSED_INPUT, + modes&winterm.ENABLE_LINE_INPUT) + fmt.Printf("ENABLE_WINDOW_INPUT=%d, ENABLE_MOUSE_INPUT=%d\n", + modes&winterm.ENABLE_WINDOW_INPUT, + modes&winterm.ENABLE_MOUSE_INPUT) + fmt.Printf("enableVirtualTerminalInput=%d, enableVirtualTerminalProcessing=%d, disableNewlineAutoReturn=%d\n", + modes&winterm.ENABLE_VIRTUAL_TERMINAL_INPUT, + modes&winterm.ENABLE_VIRTUAL_TERMINAL_PROCESSING, + modes&winterm.DISABLE_NEWLINE_AUTO_RETURN) +} diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE new file mode 100644 index 0000000000..e3d9a64d1d --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md new file mode 100644 index 0000000000..261c041e7a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/README.md @@ -0,0 +1,12 @@ +# go-ansiterm + +This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent. + +For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position. + +The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). + +See parser_test.go for examples exercising the state machine and generating appropriate function calls. + +----- +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go new file mode 100644 index 0000000000..96504a33bc --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/constants.go @@ -0,0 +1,188 @@ +package ansiterm + +const LogEnv = "DEBUG_TERMINAL" + +// ANSI constants +// References: +// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm +// -- http://man7.org/linux/man-pages/man4/console_codes.4.html +// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html +// -- http://en.wikipedia.org/wiki/ANSI_escape_code +// -- http://vt100.net/emu/dec_ansi_parser +// -- http://vt100.net/emu/vt500_parser.svg +// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html +// -- http://www.inwap.com/pdp10/ansicode.txt +const ( + // ECMA-48 Set Graphics Rendition + // Note: + // -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved + // -- Fonts could possibly be supported via SetCurrentConsoleFontEx + // -- Windows does not expose the per-window cursor (i.e., caret) blink times + ANSI_SGR_RESET = 0 + ANSI_SGR_BOLD = 1 + ANSI_SGR_DIM = 2 + _ANSI_SGR_ITALIC = 3 + ANSI_SGR_UNDERLINE = 4 + _ANSI_SGR_BLINKSLOW = 5 + _ANSI_SGR_BLINKFAST = 6 + ANSI_SGR_REVERSE = 7 + _ANSI_SGR_INVISIBLE = 8 + _ANSI_SGR_LINETHROUGH = 9 + _ANSI_SGR_FONT_00 = 10 + _ANSI_SGR_FONT_01 = 11 + _ANSI_SGR_FONT_02 = 12 + _ANSI_SGR_FONT_03 = 13 + _ANSI_SGR_FONT_04 = 14 + _ANSI_SGR_FONT_05 = 15 + _ANSI_SGR_FONT_06 = 16 + _ANSI_SGR_FONT_07 = 17 + _ANSI_SGR_FONT_08 = 18 + _ANSI_SGR_FONT_09 = 19 + _ANSI_SGR_FONT_10 = 20 + _ANSI_SGR_DOUBLEUNDERLINE = 21 + ANSI_SGR_BOLD_DIM_OFF = 22 + _ANSI_SGR_ITALIC_OFF = 23 + ANSI_SGR_UNDERLINE_OFF = 24 + _ANSI_SGR_BLINK_OFF = 25 + _ANSI_SGR_RESERVED_00 = 26 + ANSI_SGR_REVERSE_OFF = 27 + _ANSI_SGR_INVISIBLE_OFF = 28 + _ANSI_SGR_LINETHROUGH_OFF = 29 + ANSI_SGR_FOREGROUND_BLACK = 30 + ANSI_SGR_FOREGROUND_RED = 31 + ANSI_SGR_FOREGROUND_GREEN = 32 + ANSI_SGR_FOREGROUND_YELLOW = 33 + ANSI_SGR_FOREGROUND_BLUE = 34 + ANSI_SGR_FOREGROUND_MAGENTA = 35 + ANSI_SGR_FOREGROUND_CYAN = 36 + ANSI_SGR_FOREGROUND_WHITE = 37 + _ANSI_SGR_RESERVED_01 = 38 + ANSI_SGR_FOREGROUND_DEFAULT = 39 + ANSI_SGR_BACKGROUND_BLACK = 40 + ANSI_SGR_BACKGROUND_RED = 41 + ANSI_SGR_BACKGROUND_GREEN = 42 + ANSI_SGR_BACKGROUND_YELLOW = 43 + ANSI_SGR_BACKGROUND_BLUE = 44 + ANSI_SGR_BACKGROUND_MAGENTA = 45 + ANSI_SGR_BACKGROUND_CYAN = 46 + ANSI_SGR_BACKGROUND_WHITE = 47 + _ANSI_SGR_RESERVED_02 = 48 + ANSI_SGR_BACKGROUND_DEFAULT = 49 + // 50 - 65: Unsupported + + ANSI_MAX_CMD_LENGTH = 4096 + + MAX_INPUT_EVENTS = 128 + DEFAULT_WIDTH = 80 + DEFAULT_HEIGHT = 24 + + ANSI_BEL = 0x07 + ANSI_BACKSPACE = 0x08 + ANSI_TAB = 0x09 + ANSI_LINE_FEED = 0x0A + ANSI_VERTICAL_TAB = 0x0B + ANSI_FORM_FEED = 0x0C + ANSI_CARRIAGE_RETURN = 0x0D + ANSI_ESCAPE_PRIMARY = 0x1B + ANSI_ESCAPE_SECONDARY = 0x5B + ANSI_OSC_STRING_ENTRY = 0x5D + ANSI_COMMAND_FIRST = 0x40 + ANSI_COMMAND_LAST = 0x7E + DCS_ENTRY = 0x90 + CSI_ENTRY = 0x9B + OSC_STRING = 0x9D + ANSI_PARAMETER_SEP = ";" + ANSI_CMD_G0 = '(' + ANSI_CMD_G1 = ')' + ANSI_CMD_G2 = '*' + ANSI_CMD_G3 = '+' + ANSI_CMD_DECPNM = '>' + ANSI_CMD_DECPAM = '=' + ANSI_CMD_OSC = ']' + ANSI_CMD_STR_TERM = '\\' + + KEY_CONTROL_PARAM_2 = ";2" + KEY_CONTROL_PARAM_3 = ";3" + KEY_CONTROL_PARAM_4 = ";4" + KEY_CONTROL_PARAM_5 = ";5" + KEY_CONTROL_PARAM_6 = ";6" + KEY_CONTROL_PARAM_7 = ";7" + KEY_CONTROL_PARAM_8 = ";8" + KEY_ESC_CSI = "\x1B[" + KEY_ESC_N = "\x1BN" + KEY_ESC_O = "\x1BO" + + FILL_CHARACTER = ' ' +) + +func getByteRange(start byte, end byte) []byte { + bytes := make([]byte, 0, 32) + for i := start; i <= end; i++ { + bytes = append(bytes, byte(i)) + } + + return bytes +} + +var toGroundBytes = getToGroundBytes() +var executors = getExecuteBytes() + +// SPACE 20+A0 hex Always and everywhere a blank space +// Intermediate 20-2F hex !"#$%&'()*+,-./ +var intermeds = getByteRange(0x20, 0x2F) + +// Parameters 30-3F hex 0123456789:;<=>? +// CSI Parameters 30-39, 3B hex 0123456789; +var csiParams = getByteRange(0x30, 0x3F) + +var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) + +// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ +var upperCase = getByteRange(0x40, 0x5F) + +// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~ +var lowerCase = getByteRange(0x60, 0x7E) + +// Alphabetics 40-7E hex (all of upper and lower case) +var alphabetics = append(upperCase, lowerCase...) + +var printables = getByteRange(0x20, 0x7F) + +var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) +var escapeToGroundBytes = getEscapeToGroundBytes() + +// See http://www.vt100.net/emu/vt500_parser.png for description of the complex +// byte ranges below + +func getEscapeToGroundBytes() []byte { + escapeToGroundBytes := getByteRange(0x30, 0x4F) + escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...) + escapeToGroundBytes = append(escapeToGroundBytes, 0x59) + escapeToGroundBytes = append(escapeToGroundBytes, 0x5A) + escapeToGroundBytes = append(escapeToGroundBytes, 0x5C) + escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...) + return escapeToGroundBytes +} + +func getExecuteBytes() []byte { + executeBytes := getByteRange(0x00, 0x17) + executeBytes = append(executeBytes, 0x19) + executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...) + return executeBytes +} + +func getToGroundBytes() []byte { + groundBytes := []byte{0x18} + groundBytes = append(groundBytes, 0x1A) + groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...) + groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...) + groundBytes = append(groundBytes, 0x99) + groundBytes = append(groundBytes, 0x9A) + groundBytes = append(groundBytes, 0x9C) + return groundBytes +} + +// Delete 7F hex Always and everywhere ignored +// C1 Control 80-9F hex 32 additional control characters +// G1 Displayable A1-FE hex 94 additional displayable characters +// Special A0+FF hex Same as SPACE and DELETE diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go new file mode 100644 index 0000000000..8d66e777c0 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/context.go @@ -0,0 +1,7 @@ +package ansiterm + +type ansiContext struct { + currentChar byte + paramBuffer []byte + interBuffer []byte +} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go new file mode 100644 index 0000000000..bcbe00d0c5 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go @@ -0,0 +1,49 @@ +package ansiterm + +type csiEntryState struct { + baseState +} + +func (csiState csiEntryState) Handle(b byte) (s state, e error) { + csiState.parser.logf("CsiEntry::Handle %#x", b) + + nextState, err := csiState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + return csiState.parser.csiParam, nil + case sliceContains(executors, b): + return csiState, csiState.parser.execute() + } + + return csiState, nil +} + +func (csiState csiEntryState) Transition(s state) error { + csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) + csiState.baseState.Transition(s) + + switch s { + case csiState.parser.ground: + return csiState.parser.csiDispatch() + case csiState.parser.csiParam: + switch { + case sliceContains(csiParams, csiState.parser.context.currentChar): + csiState.parser.collectParam() + case sliceContains(intermeds, csiState.parser.context.currentChar): + csiState.parser.collectInter() + } + } + + return nil +} + +func (csiState csiEntryState) Enter() error { + csiState.parser.clear() + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go new file mode 100644 index 0000000000..7ed5e01c34 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go @@ -0,0 +1,38 @@ +package ansiterm + +type csiParamState struct { + baseState +} + +func (csiState csiParamState) Handle(b byte) (s state, e error) { + csiState.parser.logf("CsiParam::Handle %#x", b) + + nextState, err := csiState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(alphabetics, b): + return csiState.parser.ground, nil + case sliceContains(csiCollectables, b): + csiState.parser.collectParam() + return csiState, nil + case sliceContains(executors, b): + return csiState, csiState.parser.execute() + } + + return csiState, nil +} + +func (csiState csiParamState) Transition(s state) error { + csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) + csiState.baseState.Transition(s) + + switch s { + case csiState.parser.ground: + return csiState.parser.csiDispatch() + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go new file mode 100644 index 0000000000..1c719db9e4 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go @@ -0,0 +1,36 @@ +package ansiterm + +type escapeIntermediateState struct { + baseState +} + +func (escState escapeIntermediateState) Handle(b byte) (s state, e error) { + escState.parser.logf("escapeIntermediateState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(intermeds, b): + return escState, escState.parser.collectInter() + case sliceContains(executors, b): + return escState, escState.parser.execute() + case sliceContains(escapeIntermediateToGroundBytes, b): + return escState.parser.ground, nil + } + + return escState, nil +} + +func (escState escapeIntermediateState) Transition(s state) error { + escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) + + switch s { + case escState.parser.ground: + return escState.parser.escDispatch() + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go new file mode 100644 index 0000000000..6390abd231 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go @@ -0,0 +1,47 @@ +package ansiterm + +type escapeState struct { + baseState +} + +func (escState escapeState) Handle(b byte) (s state, e error) { + escState.parser.logf("escapeState::Handle %#x", b) + nextState, err := escState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case b == ANSI_ESCAPE_SECONDARY: + return escState.parser.csiEntry, nil + case b == ANSI_OSC_STRING_ENTRY: + return escState.parser.oscString, nil + case sliceContains(executors, b): + return escState, escState.parser.execute() + case sliceContains(escapeToGroundBytes, b): + return escState.parser.ground, nil + case sliceContains(intermeds, b): + return escState.parser.escapeIntermediate, nil + } + + return escState, nil +} + +func (escState escapeState) Transition(s state) error { + escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name()) + escState.baseState.Transition(s) + + switch s { + case escState.parser.ground: + return escState.parser.escDispatch() + case escState.parser.escapeIntermediate: + return escState.parser.collectInter() + } + + return nil +} + +func (escState escapeState) Enter() error { + escState.parser.clear() + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go new file mode 100644 index 0000000000..98087b38c2 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/event_handler.go @@ -0,0 +1,90 @@ +package ansiterm + +type AnsiEventHandler interface { + // Print + Print(b byte) error + + // Execute C0 commands + Execute(b byte) error + + // CUrsor Up + CUU(int) error + + // CUrsor Down + CUD(int) error + + // CUrsor Forward + CUF(int) error + + // CUrsor Backward + CUB(int) error + + // Cursor to Next Line + CNL(int) error + + // Cursor to Previous Line + CPL(int) error + + // Cursor Horizontal position Absolute + CHA(int) error + + // Vertical line Position Absolute + VPA(int) error + + // CUrsor Position + CUP(int, int) error + + // Horizontal and Vertical Position (depends on PUM) + HVP(int, int) error + + // Text Cursor Enable Mode + DECTCEM(bool) error + + // Origin Mode + DECOM(bool) error + + // 132 Column Mode + DECCOLM(bool) error + + // Erase in Display + ED(int) error + + // Erase in Line + EL(int) error + + // Insert Line + IL(int) error + + // Delete Line + DL(int) error + + // Insert Character + ICH(int) error + + // Delete Character + DCH(int) error + + // Set Graphics Rendition + SGR([]int) error + + // Pan Down + SU(int) error + + // Pan Up + SD(int) error + + // Device Attributes + DA([]string) error + + // Set Top and Bottom Margins + DECSTBM(int, int) error + + // Index + IND() error + + // Reverse Index + RI() error + + // Flush updates from previous commands + Flush() error +} diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go new file mode 100644 index 0000000000..52451e9469 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/ground_state.go @@ -0,0 +1,24 @@ +package ansiterm + +type groundState struct { + baseState +} + +func (gs groundState) Handle(b byte) (s state, e error) { + gs.parser.context.currentChar = b + + nextState, err := gs.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case sliceContains(printables, b): + return gs, gs.parser.print() + + case sliceContains(executors, b): + return gs, gs.parser.execute() + } + + return gs, nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go new file mode 100644 index 0000000000..593b10ab69 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go @@ -0,0 +1,31 @@ +package ansiterm + +type oscStringState struct { + baseState +} + +func (oscState oscStringState) Handle(b byte) (s state, e error) { + oscState.parser.logf("OscString::Handle %#x", b) + nextState, err := oscState.baseState.Handle(b) + if nextState != nil || err != nil { + return nextState, err + } + + switch { + case isOscStringTerminator(b): + return oscState.parser.ground, nil + } + + return oscState, nil +} + +// See below for OSC string terminators for linux +// http://man7.org/linux/man-pages/man4/console_codes.4.html +func isOscStringTerminator(b byte) bool { + + if b == ANSI_BEL || b == 0x5C { + return true + } + + return false +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go new file mode 100644 index 0000000000..03cec7ada6 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser.go @@ -0,0 +1,151 @@ +package ansiterm + +import ( + "errors" + "log" + "os" +) + +type AnsiParser struct { + currState state + eventHandler AnsiEventHandler + context *ansiContext + csiEntry state + csiParam state + dcsEntry state + escape state + escapeIntermediate state + error state + ground state + oscString state + stateMap []state + + logf func(string, ...interface{}) +} + +type Option func(*AnsiParser) + +func WithLogf(f func(string, ...interface{})) Option { + return func(ap *AnsiParser) { + ap.logf = f + } +} + +func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser { + ap := &AnsiParser{ + eventHandler: evtHandler, + context: &ansiContext{}, + } + for _, o := range opts { + o(ap) + } + + if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" { + logFile, _ := os.Create("ansiParser.log") + logger := log.New(logFile, "", log.LstdFlags) + if ap.logf != nil { + l := ap.logf + ap.logf = func(s string, v ...interface{}) { + l(s, v...) + logger.Printf(s, v...) + } + } else { + ap.logf = logger.Printf + } + } + + if ap.logf == nil { + ap.logf = func(string, ...interface{}) {} + } + + ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}} + ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}} + ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}} + ap.escape = escapeState{baseState{name: "Escape", parser: ap}} + ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}} + ap.error = errorState{baseState{name: "Error", parser: ap}} + ap.ground = groundState{baseState{name: "Ground", parser: ap}} + ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}} + + ap.stateMap = []state{ + ap.csiEntry, + ap.csiParam, + ap.dcsEntry, + ap.escape, + ap.escapeIntermediate, + ap.error, + ap.ground, + ap.oscString, + } + + ap.currState = getState(initialState, ap.stateMap) + + ap.logf("CreateParser: parser %p", ap) + return ap +} + +func getState(name string, states []state) state { + for _, el := range states { + if el.Name() == name { + return el + } + } + + return nil +} + +func (ap *AnsiParser) Parse(bytes []byte) (int, error) { + for i, b := range bytes { + if err := ap.handle(b); err != nil { + return i, err + } + } + + return len(bytes), ap.eventHandler.Flush() +} + +func (ap *AnsiParser) handle(b byte) error { + ap.context.currentChar = b + newState, err := ap.currState.Handle(b) + if err != nil { + return err + } + + if newState == nil { + ap.logf("WARNING: newState is nil") + return errors.New("New state of 'nil' is invalid.") + } + + if newState != ap.currState { + if err := ap.changeState(newState); err != nil { + return err + } + } + + return nil +} + +func (ap *AnsiParser) changeState(newState state) error { + ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name()) + + // Exit old state + if err := ap.currState.Exit(); err != nil { + ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err) + return err + } + + // Perform transition action + if err := ap.currState.Transition(newState); err != nil { + ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err) + return err + } + + // Enter new state + if err := newState.Enter(); err != nil { + ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err) + return err + } + + ap.currState = newState + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go new file mode 100644 index 0000000000..de0a1f9cde --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go @@ -0,0 +1,99 @@ +package ansiterm + +import ( + "strconv" +) + +func parseParams(bytes []byte) ([]string, error) { + paramBuff := make([]byte, 0, 0) + params := []string{} + + for _, v := range bytes { + if v == ';' { + if len(paramBuff) > 0 { + // Completed parameter, append it to the list + s := string(paramBuff) + params = append(params, s) + paramBuff = make([]byte, 0, 0) + } + } else { + paramBuff = append(paramBuff, v) + } + } + + // Last parameter may not be terminated with ';' + if len(paramBuff) > 0 { + s := string(paramBuff) + params = append(params, s) + } + + return params, nil +} + +func parseCmd(context ansiContext) (string, error) { + return string(context.currentChar), nil +} + +func getInt(params []string, dflt int) int { + i := getInts(params, 1, dflt)[0] + return i +} + +func getInts(params []string, minCount int, dflt int) []int { + ints := []int{} + + for _, v := range params { + i, _ := strconv.Atoi(v) + // Zero is mapped to the default value in VT100. + if i == 0 { + i = dflt + } + ints = append(ints, i) + } + + if len(ints) < minCount { + remaining := minCount - len(ints) + for i := 0; i < remaining; i++ { + ints = append(ints, dflt) + } + } + + return ints +} + +func (ap *AnsiParser) modeDispatch(param string, set bool) error { + switch param { + case "?3": + return ap.eventHandler.DECCOLM(set) + case "?6": + return ap.eventHandler.DECOM(set) + case "?25": + return ap.eventHandler.DECTCEM(set) + } + return nil +} + +func (ap *AnsiParser) hDispatch(params []string) error { + if len(params) == 1 { + return ap.modeDispatch(params[0], true) + } + + return nil +} + +func (ap *AnsiParser) lDispatch(params []string) error { + if len(params) == 1 { + return ap.modeDispatch(params[0], false) + } + + return nil +} + +func getEraseParam(params []string) int { + param := getInt(params, 0) + if param < 0 || 3 < param { + param = 0 + } + + return param +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go new file mode 100644 index 0000000000..0bb5e51e9a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go @@ -0,0 +1,119 @@ +package ansiterm + +func (ap *AnsiParser) collectParam() error { + currChar := ap.context.currentChar + ap.logf("collectParam %#x", currChar) + ap.context.paramBuffer = append(ap.context.paramBuffer, currChar) + return nil +} + +func (ap *AnsiParser) collectInter() error { + currChar := ap.context.currentChar + ap.logf("collectInter %#x", currChar) + ap.context.paramBuffer = append(ap.context.interBuffer, currChar) + return nil +} + +func (ap *AnsiParser) escDispatch() error { + cmd, _ := parseCmd(*ap.context) + intermeds := ap.context.interBuffer + ap.logf("escDispatch currentChar: %#x", ap.context.currentChar) + ap.logf("escDispatch: %v(%v)", cmd, intermeds) + + switch cmd { + case "D": // IND + return ap.eventHandler.IND() + case "E": // NEL, equivalent to CRLF + err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN) + if err == nil { + err = ap.eventHandler.Execute(ANSI_LINE_FEED) + } + return err + case "M": // RI + return ap.eventHandler.RI() + } + + return nil +} + +func (ap *AnsiParser) csiDispatch() error { + cmd, _ := parseCmd(*ap.context) + params, _ := parseParams(ap.context.paramBuffer) + ap.logf("Parsed params: %v with length: %d", params, len(params)) + + ap.logf("csiDispatch: %v(%v)", cmd, params) + + switch cmd { + case "@": + return ap.eventHandler.ICH(getInt(params, 1)) + case "A": + return ap.eventHandler.CUU(getInt(params, 1)) + case "B": + return ap.eventHandler.CUD(getInt(params, 1)) + case "C": + return ap.eventHandler.CUF(getInt(params, 1)) + case "D": + return ap.eventHandler.CUB(getInt(params, 1)) + case "E": + return ap.eventHandler.CNL(getInt(params, 1)) + case "F": + return ap.eventHandler.CPL(getInt(params, 1)) + case "G": + return ap.eventHandler.CHA(getInt(params, 1)) + case "H": + ints := getInts(params, 2, 1) + x, y := ints[0], ints[1] + return ap.eventHandler.CUP(x, y) + case "J": + param := getEraseParam(params) + return ap.eventHandler.ED(param) + case "K": + param := getEraseParam(params) + return ap.eventHandler.EL(param) + case "L": + return ap.eventHandler.IL(getInt(params, 1)) + case "M": + return ap.eventHandler.DL(getInt(params, 1)) + case "P": + return ap.eventHandler.DCH(getInt(params, 1)) + case "S": + return ap.eventHandler.SU(getInt(params, 1)) + case "T": + return ap.eventHandler.SD(getInt(params, 1)) + case "c": + return ap.eventHandler.DA(params) + case "d": + return ap.eventHandler.VPA(getInt(params, 1)) + case "f": + ints := getInts(params, 2, 1) + x, y := ints[0], ints[1] + return ap.eventHandler.HVP(x, y) + case "h": + return ap.hDispatch(params) + case "l": + return ap.lDispatch(params) + case "m": + return ap.eventHandler.SGR(getInts(params, 1, 0)) + case "r": + ints := getInts(params, 2, 1) + top, bottom := ints[0], ints[1] + return ap.eventHandler.DECSTBM(top, bottom) + default: + ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context) + return nil + } + +} + +func (ap *AnsiParser) print() error { + return ap.eventHandler.Print(ap.context.currentChar) +} + +func (ap *AnsiParser) clear() error { + ap.context = &ansiContext{} + return nil +} + +func (ap *AnsiParser) execute() error { + return ap.eventHandler.Execute(ap.context.currentChar) +} diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go new file mode 100644 index 0000000000..f2ea1fcd12 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/states.go @@ -0,0 +1,71 @@ +package ansiterm + +type stateID int + +type state interface { + Enter() error + Exit() error + Handle(byte) (state, error) + Name() string + Transition(state) error +} + +type baseState struct { + name string + parser *AnsiParser +} + +func (base baseState) Enter() error { + return nil +} + +func (base baseState) Exit() error { + return nil +} + +func (base baseState) Handle(b byte) (s state, e error) { + + switch { + case b == CSI_ENTRY: + return base.parser.csiEntry, nil + case b == DCS_ENTRY: + return base.parser.dcsEntry, nil + case b == ANSI_ESCAPE_PRIMARY: + return base.parser.escape, nil + case b == OSC_STRING: + return base.parser.oscString, nil + case sliceContains(toGroundBytes, b): + return base.parser.ground, nil + } + + return nil, nil +} + +func (base baseState) Name() string { + return base.name +} + +func (base baseState) Transition(s state) error { + if s == base.parser.ground { + execBytes := []byte{0x18} + execBytes = append(execBytes, 0x1A) + execBytes = append(execBytes, getByteRange(0x80, 0x8F)...) + execBytes = append(execBytes, getByteRange(0x91, 0x97)...) + execBytes = append(execBytes, 0x99) + execBytes = append(execBytes, 0x9A) + + if sliceContains(execBytes, base.parser.context.currentChar) { + return base.parser.execute() + } + } + + return nil +} + +type dcsEntryState struct { + baseState +} + +type errorState struct { + baseState +} diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go new file mode 100644 index 0000000000..392114493a --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/utilities.go @@ -0,0 +1,21 @@ +package ansiterm + +import ( + "strconv" +) + +func sliceContains(bytes []byte, b byte) bool { + for _, v := range bytes { + if v == b { + return true + } + } + + return false +} + +func convertBytesToInteger(bytes []byte) int { + s := string(bytes) + i, _ := strconv.Atoi(s) + return i +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go new file mode 100644 index 0000000000..a673279726 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go @@ -0,0 +1,182 @@ +// +build windows + +package winterm + +import ( + "fmt" + "os" + "strconv" + "strings" + "syscall" + + "github.com/Azure/go-ansiterm" +) + +// Windows keyboard constants +// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx. +const ( + VK_PRIOR = 0x21 // PAGE UP key + VK_NEXT = 0x22 // PAGE DOWN key + VK_END = 0x23 // END key + VK_HOME = 0x24 // HOME key + VK_LEFT = 0x25 // LEFT ARROW key + VK_UP = 0x26 // UP ARROW key + VK_RIGHT = 0x27 // RIGHT ARROW key + VK_DOWN = 0x28 // DOWN ARROW key + VK_SELECT = 0x29 // SELECT key + VK_PRINT = 0x2A // PRINT key + VK_EXECUTE = 0x2B // EXECUTE key + VK_SNAPSHOT = 0x2C // PRINT SCREEN key + VK_INSERT = 0x2D // INS key + VK_DELETE = 0x2E // DEL key + VK_HELP = 0x2F // HELP key + VK_F1 = 0x70 // F1 key + VK_F2 = 0x71 // F2 key + VK_F3 = 0x72 // F3 key + VK_F4 = 0x73 // F4 key + VK_F5 = 0x74 // F5 key + VK_F6 = 0x75 // F6 key + VK_F7 = 0x76 // F7 key + VK_F8 = 0x77 // F8 key + VK_F9 = 0x78 // F9 key + VK_F10 = 0x79 // F10 key + VK_F11 = 0x7A // F11 key + VK_F12 = 0x7B // F12 key + + RIGHT_ALT_PRESSED = 0x0001 + LEFT_ALT_PRESSED = 0x0002 + RIGHT_CTRL_PRESSED = 0x0004 + LEFT_CTRL_PRESSED = 0x0008 + SHIFT_PRESSED = 0x0010 + NUMLOCK_ON = 0x0020 + SCROLLLOCK_ON = 0x0040 + CAPSLOCK_ON = 0x0080 + ENHANCED_KEY = 0x0100 +) + +type ansiCommand struct { + CommandBytes []byte + Command string + Parameters []string + IsSpecial bool +} + +func newAnsiCommand(command []byte) *ansiCommand { + + if isCharacterSelectionCmdChar(command[1]) { + // Is Character Set Selection commands + return &ansiCommand{ + CommandBytes: command, + Command: string(command), + IsSpecial: true, + } + } + + // last char is command character + lastCharIndex := len(command) - 1 + + ac := &ansiCommand{ + CommandBytes: command, + Command: string(command[lastCharIndex]), + IsSpecial: false, + } + + // more than a single escape + if lastCharIndex != 0 { + start := 1 + // skip if double char escape sequence + if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY { + start++ + } + // convert this to GetNextParam method + ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP) + } + + return ac +} + +func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 { + if index < 0 || index >= len(ac.Parameters) { + return defaultValue + } + + param, err := strconv.ParseInt(ac.Parameters[index], 10, 16) + if err != nil { + return defaultValue + } + + return int16(param) +} + +func (ac *ansiCommand) String() string { + return fmt.Sprintf("0x%v \"%v\" (\"%v\")", + bytesToHex(ac.CommandBytes), + ac.Command, + strings.Join(ac.Parameters, "\",\"")) +} + +// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands. +// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. +func isAnsiCommandChar(b byte) bool { + switch { + case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY: + return true + case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM: + // non-CSI escape sequence terminator + return true + case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL: + // String escape sequence terminator + return true + } + return false +} + +func isXtermOscSequence(command []byte, current byte) bool { + return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL) +} + +func isCharacterSelectionCmdChar(b byte) bool { + return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3) +} + +// bytesToHex converts a slice of bytes to a human-readable string. +func bytesToHex(b []byte) string { + hex := make([]string, len(b)) + for i, ch := range b { + hex[i] = fmt.Sprintf("%X", ch) + } + return strings.Join(hex, "") +} + +// ensureInRange adjusts the passed value, if necessary, to ensure it is within +// the passed min / max range. +func ensureInRange(n int16, min int16, max int16) int16 { + if n < min { + return min + } else if n > max { + return max + } else { + return n + } +} + +func GetStdFile(nFile int) (*os.File, uintptr) { + var file *os.File + switch nFile { + case syscall.STD_INPUT_HANDLE: + file = os.Stdin + case syscall.STD_OUTPUT_HANDLE: + file = os.Stdout + case syscall.STD_ERROR_HANDLE: + file = os.Stderr + default: + panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile)) + } + + fd, err := syscall.GetStdHandle(nFile) + if err != nil { + panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err)) + } + + return file, uintptr(fd) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go new file mode 100644 index 0000000000..6055e33b91 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/api.go @@ -0,0 +1,327 @@ +// +build windows + +package winterm + +import ( + "fmt" + "syscall" + "unsafe" +) + +//=========================================================================================================== +// IMPORTANT NOTE: +// +// The methods below make extensive use of the "unsafe" package to obtain the required pointers. +// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack +// variables) the pointers reference *before* the API completes. +// +// As a result, in those cases, the code must hint that the variables remain in active by invoking the +// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer +// require unsafe pointers. +// +// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform +// the garbage collector the variables remain in use if: +// +// -- The value is not a pointer (e.g., int32, struct) +// -- The value is not referenced by the method after passing the pointer to Windows +// +// See http://golang.org/doc/go1.3. +//=========================================================================================================== + +var ( + kernel32DLL = syscall.NewLazyDLL("kernel32.dll") + + getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo") + setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo") + setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition") + setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode") + getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") + setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize") + scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA") + setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute") + setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo") + writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW") + readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW") + waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject") +) + +// Windows Console constants +const ( + // Console modes + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. + ENABLE_PROCESSED_INPUT = 0x0001 + ENABLE_LINE_INPUT = 0x0002 + ENABLE_ECHO_INPUT = 0x0004 + ENABLE_WINDOW_INPUT = 0x0008 + ENABLE_MOUSE_INPUT = 0x0010 + ENABLE_INSERT_MODE = 0x0020 + ENABLE_QUICK_EDIT_MODE = 0x0040 + ENABLE_EXTENDED_FLAGS = 0x0080 + ENABLE_AUTO_POSITION = 0x0100 + ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200 + + ENABLE_PROCESSED_OUTPUT = 0x0001 + ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + DISABLE_NEWLINE_AUTO_RETURN = 0x0008 + ENABLE_LVB_GRID_WORLDWIDE = 0x0010 + + // Character attributes + // Note: + // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). + // Clearing all foreground or background colors results in black; setting all creates white. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. + FOREGROUND_BLUE uint16 = 0x0001 + FOREGROUND_GREEN uint16 = 0x0002 + FOREGROUND_RED uint16 = 0x0004 + FOREGROUND_INTENSITY uint16 = 0x0008 + FOREGROUND_MASK uint16 = 0x000F + + BACKGROUND_BLUE uint16 = 0x0010 + BACKGROUND_GREEN uint16 = 0x0020 + BACKGROUND_RED uint16 = 0x0040 + BACKGROUND_INTENSITY uint16 = 0x0080 + BACKGROUND_MASK uint16 = 0x00F0 + + COMMON_LVB_MASK uint16 = 0xFF00 + COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000 + COMMON_LVB_UNDERSCORE uint16 = 0x8000 + + // Input event types + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. + KEY_EVENT = 0x0001 + MOUSE_EVENT = 0x0002 + WINDOW_BUFFER_SIZE_EVENT = 0x0004 + MENU_EVENT = 0x0008 + FOCUS_EVENT = 0x0010 + + // WaitForSingleObject return codes + WAIT_ABANDONED = 0x00000080 + WAIT_FAILED = 0xFFFFFFFF + WAIT_SIGNALED = 0x0000000 + WAIT_TIMEOUT = 0x00000102 + + // WaitForSingleObject wait duration + WAIT_INFINITE = 0xFFFFFFFF + WAIT_ONE_SECOND = 1000 + WAIT_HALF_SECOND = 500 + WAIT_QUARTER_SECOND = 250 +) + +// Windows API Console types +// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD) +// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment +type ( + CHAR_INFO struct { + UnicodeChar uint16 + Attributes uint16 + } + + CONSOLE_CURSOR_INFO struct { + Size uint32 + Visible int32 + } + + CONSOLE_SCREEN_BUFFER_INFO struct { + Size COORD + CursorPosition COORD + Attributes uint16 + Window SMALL_RECT + MaximumWindowSize COORD + } + + COORD struct { + X int16 + Y int16 + } + + SMALL_RECT struct { + Left int16 + Top int16 + Right int16 + Bottom int16 + } + + // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. + INPUT_RECORD struct { + EventType uint16 + KeyEvent KEY_EVENT_RECORD + } + + KEY_EVENT_RECORD struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + UnicodeChar uint16 + ControlKeyState uint32 + } + + WINDOW_BUFFER_SIZE struct { + Size COORD + } +) + +// boolToBOOL converts a Go bool into a Windows int32. +func boolToBOOL(f bool) int32 { + if f { + return int32(1) + } else { + return int32(0) + } +} + +// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx. +func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { + r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) + return checkError(r1, r2, err) +} + +// SetConsoleCursorInfo sets the size and visiblity of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx. +func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error { + r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0) + return checkError(r1, r2, err) +} + +// SetConsoleCursorPosition location of the console cursor. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx. +func SetConsoleCursorPosition(handle uintptr, coord COORD) error { + r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord)) + use(coord) + return checkError(r1, r2, err) +} + +// GetConsoleMode gets the console mode for given file descriptor +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx. +func GetConsoleMode(handle uintptr) (mode uint32, err error) { + err = syscall.GetConsoleMode(syscall.Handle(handle), &mode) + return mode, err +} + +// SetConsoleMode sets the console mode for given file descriptor +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx. +func SetConsoleMode(handle uintptr, mode uint32) error { + r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0) + use(mode) + return checkError(r1, r2, err) +} + +// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx. +func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { + info := CONSOLE_SCREEN_BUFFER_INFO{} + err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)) + if err != nil { + return nil, err + } + return &info, nil +} + +func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error { + r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char))) + use(scrollRect) + use(clipRect) + use(destOrigin) + use(char) + return checkError(r1, r2, err) +} + +// SetConsoleScreenBufferSize sets the size of the console screen buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx. +func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error { + r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord)) + use(coord) + return checkError(r1, r2, err) +} + +// SetConsoleTextAttribute sets the attributes of characters written to the +// console screen buffer by the WriteFile or WriteConsole function. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. +func SetConsoleTextAttribute(handle uintptr, attribute uint16) error { + r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0) + use(attribute) + return checkError(r1, r2, err) +} + +// SetConsoleWindowInfo sets the size and position of the console screen buffer's window. +// Note that the size and location must be within and no larger than the backing console screen buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx. +func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error { + r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect))) + use(isAbsolute) + use(rect) + return checkError(r1, r2, err) +} + +// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx. +func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error { + r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion))) + use(buffer) + use(bufferSize) + use(bufferCoord) + return checkError(r1, r2, err) +} + +// ReadConsoleInput reads (and removes) data from the console input buffer. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx. +func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error { + r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count))) + use(buffer) + return checkError(r1, r2, err) +} + +// WaitForSingleObject waits for the passed handle to be signaled. +// It returns true if the handle was signaled; false otherwise. +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx. +func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) { + r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait))) + switch r1 { + case WAIT_ABANDONED, WAIT_TIMEOUT: + return false, nil + case WAIT_SIGNALED: + return true, nil + } + use(msWait) + return false, err +} + +// String helpers +func (info CONSOLE_SCREEN_BUFFER_INFO) String() string { + return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize) +} + +func (coord COORD) String() string { + return fmt.Sprintf("%v,%v", coord.X, coord.Y) +} + +func (rect SMALL_RECT) String() string { + return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom) +} + +// checkError evaluates the results of a Windows API call and returns the error if it failed. +func checkError(r1, r2 uintptr, err error) error { + // Windows APIs return non-zero to indicate success + if r1 != 0 { + return nil + } + + // Return the error if provided, otherwise default to EINVAL + if err != nil { + return err + } + return syscall.EINVAL +} + +// coordToPointer converts a COORD into a uintptr (by fooling the type system). +func coordToPointer(c COORD) uintptr { + // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass. + return uintptr(*((*uint32)(unsafe.Pointer(&c)))) +} + +// use is a no-op, but the compiler cannot see that it is. +// Calling use(p) ensures that p is kept live until that point. +func use(p interface{}) {} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go new file mode 100644 index 0000000000..cbec8f728f --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go @@ -0,0 +1,100 @@ +// +build windows + +package winterm + +import "github.com/Azure/go-ansiterm" + +const ( + FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE + BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE +) + +// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the +// request represented by the passed ANSI mode. +func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) { + switch ansiMode { + + // Mode styles + case ansiterm.ANSI_SGR_BOLD: + windowsMode = windowsMode | FOREGROUND_INTENSITY + + case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF: + windowsMode &^= FOREGROUND_INTENSITY + + case ansiterm.ANSI_SGR_UNDERLINE: + windowsMode = windowsMode | COMMON_LVB_UNDERSCORE + + case ansiterm.ANSI_SGR_REVERSE: + inverted = true + + case ansiterm.ANSI_SGR_REVERSE_OFF: + inverted = false + + case ansiterm.ANSI_SGR_UNDERLINE_OFF: + windowsMode &^= COMMON_LVB_UNDERSCORE + + // Foreground colors + case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT: + windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK) + + case ansiterm.ANSI_SGR_FOREGROUND_BLACK: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) + + case ansiterm.ANSI_SGR_FOREGROUND_RED: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED + + case ansiterm.ANSI_SGR_FOREGROUND_GREEN: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN + + case ansiterm.ANSI_SGR_FOREGROUND_YELLOW: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN + + case ansiterm.ANSI_SGR_FOREGROUND_BLUE: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_CYAN: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE + + case ansiterm.ANSI_SGR_FOREGROUND_WHITE: + windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE + + // Background colors + case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT: + // Black with no intensity + windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK) + + case ansiterm.ANSI_SGR_BACKGROUND_BLACK: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) + + case ansiterm.ANSI_SGR_BACKGROUND_RED: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED + + case ansiterm.ANSI_SGR_BACKGROUND_GREEN: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN + + case ansiterm.ANSI_SGR_BACKGROUND_YELLOW: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN + + case ansiterm.ANSI_SGR_BACKGROUND_BLUE: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_CYAN: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE + + case ansiterm.ANSI_SGR_BACKGROUND_WHITE: + windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE + } + + return windowsMode, inverted +} + +// invertAttributes inverts the foreground and background colors of a Windows attributes value +func invertAttributes(windowsMode uint16) uint16 { + return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go new file mode 100644 index 0000000000..3ee06ea728 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go @@ -0,0 +1,101 @@ +// +build windows + +package winterm + +const ( + horizontal = iota + vertical +) + +func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { + if h.originMode { + sr := h.effectiveSr(info.Window) + return SMALL_RECT{ + Top: sr.top, + Bottom: sr.bottom, + Left: 0, + Right: info.Size.X - 1, + } + } else { + return SMALL_RECT{ + Top: info.Window.Top, + Bottom: info.Window.Bottom, + Left: 0, + Right: info.Size.X - 1, + } + } +} + +// setCursorPosition sets the cursor to the specified position, bounded to the screen size +func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { + position.X = ensureInRange(position.X, window.Left, window.Right) + position.Y = ensureInRange(position.Y, window.Top, window.Bottom) + err := SetConsoleCursorPosition(h.fd, position) + if err != nil { + return err + } + h.logf("Cursor position set: (%d, %d)", position.X, position.Y) + return err +} + +func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error { + return h.moveCursor(vertical, param) +} + +func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error { + return h.moveCursor(horizontal, param) +} + +func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + switch moveMode { + case horizontal: + position.X += int16(param) + case vertical: + position.Y += int16(param) + } + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) moveCursorLine(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + position.X = 0 + position.Y += int16(param) + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + position := info.CursorPosition + position.X = int16(param) - 1 + + if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go new file mode 100644 index 0000000000..244b5fa25e --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go @@ -0,0 +1,84 @@ +// +build windows + +package winterm + +import "github.com/Azure/go-ansiterm" + +func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error { + // Ignore an invalid (negative area) request + if toCoord.Y < fromCoord.Y { + return nil + } + + var err error + + var coordStart = COORD{} + var coordEnd = COORD{} + + xCurrent, yCurrent := fromCoord.X, fromCoord.Y + xEnd, yEnd := toCoord.X, toCoord.Y + + // Clear any partial initial line + if xCurrent > 0 { + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yCurrent + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + xCurrent = 0 + yCurrent += 1 + } + + // Clear intervening rectangular section + if yCurrent < yEnd { + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yEnd-1 + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + xCurrent = 0 + yCurrent = yEnd + } + + // Clear remaining partial ending line + coordStart.X, coordStart.Y = xCurrent, yCurrent + coordEnd.X, coordEnd.Y = xEnd, yEnd + + err = h.clearRect(attributes, coordStart, coordEnd) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error { + region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X} + width := toCoord.X - fromCoord.X + 1 + height := toCoord.Y - fromCoord.Y + 1 + size := uint32(width) * uint32(height) + + if size <= 0 { + return nil + } + + buffer := make([]CHAR_INFO, size) + + char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes} + for i := 0; i < int(size); i++ { + buffer[i] = char + } + + err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go new file mode 100644 index 0000000000..2d27fa1d02 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go @@ -0,0 +1,118 @@ +// +build windows + +package winterm + +// effectiveSr gets the current effective scroll region in buffer coordinates +func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { + top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom) + bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) + if top >= bottom { + top = window.Top + bottom = window.Bottom + } + return scrollRegion{top: top, bottom: bottom} +} + +func (h *windowsAnsiEventHandler) scrollUp(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + sr := h.effectiveSr(info.Window) + return h.scroll(param, sr, info) +} + +func (h *windowsAnsiEventHandler) scrollDown(param int) error { + return h.scrollUp(-param) +} + +func (h *windowsAnsiEventHandler) deleteLines(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + start := info.CursorPosition.Y + sr := h.effectiveSr(info.Window) + // Lines cannot be inserted or deleted outside the scrolling region. + if start >= sr.top && start <= sr.bottom { + sr.top = start + return h.scroll(param, sr, info) + } else { + return nil + } +} + +func (h *windowsAnsiEventHandler) insertLines(param int) error { + return h.deleteLines(-param) +} + +// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates. +func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { + h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom) + h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom) + + // Copy from and clip to the scroll region (full buffer width) + scrollRect := SMALL_RECT{ + Top: sr.top, + Bottom: sr.bottom, + Left: 0, + Right: info.Size.X - 1, + } + + // Origin to which area should be copied + destOrigin := COORD{ + X: 0, + Y: sr.top - int16(param), + } + + char := CHAR_INFO{ + UnicodeChar: ' ', + Attributes: h.attributes, + } + + if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { + return err + } + return nil +} + +func (h *windowsAnsiEventHandler) deleteCharacters(param int) error { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + return h.scrollLine(param, info.CursorPosition, info) +} + +func (h *windowsAnsiEventHandler) insertCharacters(param int) error { + return h.deleteCharacters(-param) +} + +// scrollLine scrolls a line horizontally starting at the provided position by a number of columns. +func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { + // Copy from and clip to the scroll region (full buffer width) + scrollRect := SMALL_RECT{ + Top: position.Y, + Bottom: position.Y, + Left: position.X, + Right: info.Size.X - 1, + } + + // Origin to which area should be copied + destOrigin := COORD{ + X: position.X - int16(columns), + Y: position.Y, + } + + char := CHAR_INFO{ + UnicodeChar: ' ', + Attributes: h.attributes, + } + + if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go new file mode 100644 index 0000000000..afa7635d77 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go @@ -0,0 +1,9 @@ +// +build windows + +package winterm + +// AddInRange increments a value by the passed quantity while ensuring the values +// always remain within the supplied min / max range. +func addInRange(n int16, increment int16, min int16, max int16) int16 { + return ensureInRange(n+increment, min, max) +} diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go new file mode 100644 index 0000000000..2d40fb75ad --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go @@ -0,0 +1,743 @@ +// +build windows + +package winterm + +import ( + "bytes" + "log" + "os" + "strconv" + + "github.com/Azure/go-ansiterm" +) + +type windowsAnsiEventHandler struct { + fd uintptr + file *os.File + infoReset *CONSOLE_SCREEN_BUFFER_INFO + sr scrollRegion + buffer bytes.Buffer + attributes uint16 + inverted bool + wrapNext bool + drewMarginByte bool + originMode bool + marginByte byte + curInfo *CONSOLE_SCREEN_BUFFER_INFO + curPos COORD + logf func(string, ...interface{}) +} + +type Option func(*windowsAnsiEventHandler) + +func WithLogf(f func(string, ...interface{})) Option { + return func(w *windowsAnsiEventHandler) { + w.logf = f + } +} + +func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler { + infoReset, err := GetConsoleScreenBufferInfo(fd) + if err != nil { + return nil + } + + h := &windowsAnsiEventHandler{ + fd: fd, + file: file, + infoReset: infoReset, + attributes: infoReset.Attributes, + } + for _, o := range opts { + o(h) + } + + if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { + logFile, _ := os.Create("winEventHandler.log") + logger := log.New(logFile, "", log.LstdFlags) + if h.logf != nil { + l := h.logf + h.logf = func(s string, v ...interface{}) { + l(s, v...) + logger.Printf(s, v...) + } + } else { + h.logf = logger.Printf + } + } + + if h.logf == nil { + h.logf = func(string, ...interface{}) {} + } + + return h +} + +type scrollRegion struct { + top int16 + bottom int16 +} + +// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the +// current cursor position and scroll region settings, in which case it returns +// true. If no special handling is necessary, then it does nothing and returns +// false. +// +// In the false case, the caller should ensure that a carriage return +// and line feed are inserted or that the text is otherwise wrapped. +func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { + if h.wrapNext { + if err := h.Flush(); err != nil { + return false, err + } + h.clearWrap() + } + pos, info, err := h.getCurrentInfo() + if err != nil { + return false, err + } + sr := h.effectiveSr(info.Window) + if pos.Y == sr.bottom { + // Scrolling is necessary. Let Windows automatically scroll if the scrolling region + // is the full window. + if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom { + if includeCR { + pos.X = 0 + h.updatePos(pos) + } + return false, nil + } + + // A custom scroll region is active. Scroll the window manually to simulate + // the LF. + if err := h.Flush(); err != nil { + return false, err + } + h.logf("Simulating LF inside scroll region") + if err := h.scrollUp(1); err != nil { + return false, err + } + if includeCR { + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return false, err + } + } + return true, nil + + } else if pos.Y < info.Window.Bottom { + // Let Windows handle the LF. + pos.Y++ + if includeCR { + pos.X = 0 + } + h.updatePos(pos) + return false, nil + } else { + // The cursor is at the bottom of the screen but outside the scroll + // region. Skip the LF. + h.logf("Simulating LF outside scroll region") + if includeCR { + if err := h.Flush(); err != nil { + return false, err + } + pos.X = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return false, err + } + } + return true, nil + } +} + +// executeLF executes a LF without a CR. +func (h *windowsAnsiEventHandler) executeLF() error { + handled, err := h.simulateLF(false) + if err != nil { + return err + } + if !handled { + // Windows LF will reset the cursor column position. Write the LF + // and restore the cursor position. + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) + if pos.X != 0 { + if err := h.Flush(); err != nil { + return err + } + h.logf("Resetting cursor position for LF without CR") + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + } + } + return nil +} + +func (h *windowsAnsiEventHandler) Print(b byte) error { + if h.wrapNext { + h.buffer.WriteByte(h.marginByte) + h.clearWrap() + if _, err := h.simulateLF(true); err != nil { + return err + } + } + pos, info, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X == info.Size.X-1 { + h.wrapNext = true + h.marginByte = b + } else { + pos.X++ + h.updatePos(pos) + h.buffer.WriteByte(b) + } + return nil +} + +func (h *windowsAnsiEventHandler) Execute(b byte) error { + switch b { + case ansiterm.ANSI_TAB: + h.logf("Execute(TAB)") + // Move to the next tab stop, but preserve auto-wrap if already set. + if !h.wrapNext { + pos, info, err := h.getCurrentInfo() + if err != nil { + return err + } + pos.X = (pos.X + 8) - pos.X%8 + if pos.X >= info.Size.X { + pos.X = info.Size.X - 1 + } + if err := h.Flush(); err != nil { + return err + } + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + } + return nil + + case ansiterm.ANSI_BEL: + h.buffer.WriteByte(ansiterm.ANSI_BEL) + return nil + + case ansiterm.ANSI_BACKSPACE: + if h.wrapNext { + if err := h.Flush(); err != nil { + return err + } + h.clearWrap() + } + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X > 0 { + pos.X-- + h.updatePos(pos) + h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE) + } + return nil + + case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED: + // Treat as true LF. + return h.executeLF() + + case ansiterm.ANSI_LINE_FEED: + // Simulate a CR and LF for now since there is no way in go-ansiterm + // to tell if the LF should include CR (and more things break when it's + // missing than when it's incorrectly added). + handled, err := h.simulateLF(true) + if handled || err != nil { + return err + } + return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED) + + case ansiterm.ANSI_CARRIAGE_RETURN: + if h.wrapNext { + if err := h.Flush(); err != nil { + return err + } + h.clearWrap() + } + pos, _, err := h.getCurrentInfo() + if err != nil { + return err + } + if pos.X != 0 { + pos.X = 0 + h.updatePos(pos) + h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN) + } + return nil + + default: + return nil + } +} + +func (h *windowsAnsiEventHandler) CUU(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUU: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorVertical(-param) +} + +func (h *windowsAnsiEventHandler) CUD(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUD: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorVertical(param) +} + +func (h *windowsAnsiEventHandler) CUF(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUF: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorHorizontal(param) +} + +func (h *windowsAnsiEventHandler) CUB(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUB: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorHorizontal(-param) +} + +func (h *windowsAnsiEventHandler) CNL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CNL: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorLine(param) +} + +func (h *windowsAnsiEventHandler) CPL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CPL: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorLine(-param) +} + +func (h *windowsAnsiEventHandler) CHA(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CHA: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.moveCursorColumn(param) +} + +func (h *windowsAnsiEventHandler) VPA(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("VPA: [[%d]]", param) + h.clearWrap() + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + window := h.getCursorWindow(info) + position := info.CursorPosition + position.Y = window.Top + int16(param) - 1 + return h.setCursorPosition(position, window) +} + +func (h *windowsAnsiEventHandler) CUP(row int, col int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("CUP: [[%d %d]]", row, col) + h.clearWrap() + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + window := h.getCursorWindow(info) + position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1} + return h.setCursorPosition(position, window) +} + +func (h *windowsAnsiEventHandler) HVP(row int, col int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("HVP: [[%d %d]]", row, col) + h.clearWrap() + return h.CUP(row, col) +} + +func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)}) + h.clearWrap() + return nil +} + +func (h *windowsAnsiEventHandler) DECOM(enable bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)}) + h.clearWrap() + h.originMode = enable + return h.CUP(1, 1) +} + +func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)}) + h.clearWrap() + if err := h.ED(2); err != nil { + return err + } + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + targetWidth := int16(80) + if use132 { + targetWidth = 132 + } + if info.Size.X < targetWidth { + if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { + h.logf("set buffer failed: %v", err) + return err + } + } + window := info.Window + window.Left = 0 + window.Right = targetWidth - 1 + if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { + h.logf("set window failed: %v", err) + return err + } + if info.Size.X > targetWidth { + if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil { + h.logf("set buffer failed: %v", err) + return err + } + } + return SetConsoleCursorPosition(h.fd, COORD{0, 0}) +} + +func (h *windowsAnsiEventHandler) ED(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("ED: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + + // [J -- Erases from the cursor to the end of the screen, including the cursor position. + // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position. + // [2J -- Erases the complete display. The cursor does not move. + // Notes: + // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + var start COORD + var end COORD + + switch param { + case 0: + start = info.CursorPosition + end = COORD{info.Size.X - 1, info.Size.Y - 1} + + case 1: + start = COORD{0, 0} + end = info.CursorPosition + + case 2: + start = COORD{0, 0} + end = COORD{info.Size.X - 1, info.Size.Y - 1} + } + + err = h.clearRange(h.attributes, start, end) + if err != nil { + return err + } + + // If the whole buffer was cleared, move the window to the top while preserving + // the window-relative cursor position. + if param == 2 { + pos := info.CursorPosition + window := info.Window + pos.Y -= window.Top + window.Bottom -= window.Top + window.Top = 0 + if err := SetConsoleCursorPosition(h.fd, pos); err != nil { + return err + } + if err := SetConsoleWindowInfo(h.fd, true, window); err != nil { + return err + } + } + + return nil +} + +func (h *windowsAnsiEventHandler) EL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("EL: [%v]", strconv.Itoa(param)) + h.clearWrap() + + // [K -- Erases from the cursor to the end of the line, including the cursor position. + // [1K -- Erases from the beginning of the line to the cursor, including the cursor position. + // [2K -- Erases the complete line. + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + var start COORD + var end COORD + + switch param { + case 0: + start = info.CursorPosition + end = COORD{info.Size.X, info.CursorPosition.Y} + + case 1: + start = COORD{0, info.CursorPosition.Y} + end = info.CursorPosition + + case 2: + start = COORD{0, info.CursorPosition.Y} + end = COORD{info.Size.X, info.CursorPosition.Y} + } + + err = h.clearRange(h.attributes, start, end) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) IL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("IL: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.insertLines(param) +} + +func (h *windowsAnsiEventHandler) DL(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DL: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.deleteLines(param) +} + +func (h *windowsAnsiEventHandler) ICH(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("ICH: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.insertCharacters(param) +} + +func (h *windowsAnsiEventHandler) DCH(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DCH: [%v]", strconv.Itoa(param)) + h.clearWrap() + return h.deleteCharacters(param) +} + +func (h *windowsAnsiEventHandler) SGR(params []int) error { + if err := h.Flush(); err != nil { + return err + } + strings := []string{} + for _, v := range params { + strings = append(strings, strconv.Itoa(v)) + } + + h.logf("SGR: [%v]", strings) + + if len(params) <= 0 { + h.attributes = h.infoReset.Attributes + h.inverted = false + } else { + for _, attr := range params { + + if attr == ansiterm.ANSI_SGR_RESET { + h.attributes = h.infoReset.Attributes + h.inverted = false + continue + } + + h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr)) + } + } + + attributes := h.attributes + if h.inverted { + attributes = invertAttributes(attributes) + } + err := SetConsoleTextAttribute(h.fd, attributes) + if err != nil { + return err + } + + return nil +} + +func (h *windowsAnsiEventHandler) SU(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("SU: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.scrollUp(param) +} + +func (h *windowsAnsiEventHandler) SD(param int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("SD: [%v]", []string{strconv.Itoa(param)}) + h.clearWrap() + return h.scrollDown(param) +} + +func (h *windowsAnsiEventHandler) DA(params []string) error { + h.logf("DA: [%v]", params) + // DA cannot be implemented because it must send data on the VT100 input stream, + // which is not available to go-ansiterm. + return nil +} + +func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error { + if err := h.Flush(); err != nil { + return err + } + h.logf("DECSTBM: [%d, %d]", top, bottom) + + // Windows is 0 indexed, Linux is 1 indexed + h.sr.top = int16(top - 1) + h.sr.bottom = int16(bottom - 1) + + // This command also moves the cursor to the origin. + h.clearWrap() + return h.CUP(1, 1) +} + +func (h *windowsAnsiEventHandler) RI() error { + if err := h.Flush(); err != nil { + return err + } + h.logf("RI: []") + h.clearWrap() + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + sr := h.effectiveSr(info.Window) + if info.CursorPosition.Y == sr.top { + return h.scrollDown(1) + } + + return h.moveCursorVertical(-1) +} + +func (h *windowsAnsiEventHandler) IND() error { + h.logf("IND: []") + return h.executeLF() +} + +func (h *windowsAnsiEventHandler) Flush() error { + h.curInfo = nil + if h.buffer.Len() > 0 { + h.logf("Flush: [%s]", h.buffer.Bytes()) + if _, err := h.buffer.WriteTo(h.file); err != nil { + return err + } + } + + if h.wrapNext && !h.drewMarginByte { + h.logf("Flush: drawing margin byte '%c'", h.marginByte) + + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return err + } + + charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}} + size := COORD{1, 1} + position := COORD{0, 0} + region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y} + if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil { + return err + } + h.drewMarginByte = true + } + return nil +} + +// cacheConsoleInfo ensures that the current console screen information has been queried +// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos. +func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { + if h.curInfo == nil { + info, err := GetConsoleScreenBufferInfo(h.fd) + if err != nil { + return COORD{}, nil, err + } + h.curInfo = info + h.curPos = info.CursorPosition + } + return h.curPos, h.curInfo, nil +} + +func (h *windowsAnsiEventHandler) updatePos(pos COORD) { + if h.curInfo == nil { + panic("failed to call getCurrentInfo before calling updatePos") + } + h.curPos = pos +} + +// clearWrap clears the state where the cursor is in the margin +// waiting for the next character before wrapping the line. This must +// be done before most operations that act on the cursor. +func (h *windowsAnsiEventHandler) clearWrap() { + h.wrapNext = false + h.drewMarginByte = false +} diff --git a/vendor/github.com/skycoin/dmsg/.gitignore b/vendor/github.com/skycoin/dmsg/.gitignore index 553a6e7917..cd9864fccf 100644 --- a/vendor/github.com/skycoin/dmsg/.gitignore +++ b/vendor/github.com/skycoin/dmsg/.gitignore @@ -19,3 +19,4 @@ bin/ /dmsgpty-ui /hello.txt +/integration/integration-pids.csv diff --git a/vendor/github.com/skycoin/dmsg/Makefile b/vendor/github.com/skycoin/dmsg/Makefile index 21d6c3f4d0..75440c6f1e 100644 --- a/vendor/github.com/skycoin/dmsg/Makefile +++ b/vendor/github.com/skycoin/dmsg/Makefile @@ -1,4 +1,8 @@ -SHELL := /bin/bash +ifeq ($(OS),Windows_NT) + SHELL := pwsh +else + SHELL := /bin/bash +endif .DEFAULT_GOAL := help .PHONY : check lint install-linters dep test build @@ -6,12 +10,21 @@ SHELL := /bin/bash VERSION := $(shell git describe --always) RFC_3339 := "+%Y-%m-%dT%H:%M:%SZ" -DATE := $(shell date -u $(RFC_3339)) COMMIT := $(shell git rev-list -1 HEAD) -BIN := ${PWD}/bin +ifeq ($(OS),Windows_NT) + BIN := .\bin + BIN_DIR?=.\bin + CMD_DIR := .\cmd + DATE := $(shell powershell -Command date -u ${RFC_3339}) +else + BIN := ${PWD}/bin + BIN_DIR?=./bin + CMD_DIR := ./cmd + DATE := $(shell date -u ${RFC_3339}) +endif + OPTS?=GO111MODULE=on -BIN_DIR?=./bin TEST_OPTS:=-tags no_ci -cover -timeout=5m @@ -67,7 +80,11 @@ install: ## Install `dmsg-discovery`, `dmsg-server`, `dmsgget`,`dmsgpty-cli`, `d ${OPTS} go install ${BUILD_OPTS} ./cmd/* build: ## Build binaries into ./bin - mkdir -p ${BIN}; go build ${BUILD_OPTS} -o ${BIN} ./cmd/* + mkdir -p ${BIN}; go build ${BUILD_OPTS} -o ${BIN} ${CMD_DIR}/* + +build-windows: + powershell -Command new-item ${BIN} -itemtype directory -force + powershell 'Get-ChildItem ${CMD_DIR} | % { go build ${BUILD_OPTS} -o ${BIN} $$_.FullName }' build-deploy: ## Build for deployment Docker images go build -tags netgo ${BUILD_OPTS_DEPLOY} -o /release/dmsg-discovery ./cmd/dmsg-discovery @@ -105,5 +122,11 @@ attach-pty: ## Attach local dmsgpty tmux session. stop-all: stop-pty stop-dmsg stop-db ## Stop all local tmux sessions. +integration-windows-start: + powershell -Command .\integration\integration.ps1 start + +integration-windows-stop: + powershell -Command .\integration\integration.ps1 stop + help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/vendor/github.com/skycoin/dmsg/client.go b/vendor/github.com/skycoin/dmsg/client.go index ade841f210..ddc7d770f5 100644 --- a/vendor/github.com/skycoin/dmsg/client.go +++ b/vendor/github.com/skycoin/dmsg/client.go @@ -106,7 +106,7 @@ func NewClient(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Conf c.EntityCommon.init(pk, sk, dc, log, conf.UpdateInterval) // Init callback: on set session. - c.EntityCommon.setSessionCallback = func(ctx context.Context, sessionCount int) error { + c.EntityCommon.setSessionCallback = func(ctx context.Context) error { if err := c.EntityCommon.updateClientEntry(ctx, c.done); err != nil { return err } @@ -118,7 +118,7 @@ func NewClient(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Conf } // Init callback: on delete session. - c.EntityCommon.delSessionCallback = func(ctx context.Context, sessionCount int) error { + c.EntityCommon.delSessionCallback = func(ctx context.Context) error { err := c.EntityCommon.updateClientEntry(ctx, c.done) return err } @@ -149,9 +149,6 @@ func (ce *Client) Serve(ctx context.Context) { } }(cancellabelCtx) - // Ensure we start updateClientEntryLoop once only. - updateEntryLoopOnce := new(sync.Once) - for { if isClosed(ce.done) { return @@ -197,9 +194,6 @@ func (ce *Client) Serve(ctx context.Context) { } time.Sleep(serveWait) } - - // Only start the update entry loop once we have at least one session established. - updateEntryLoopOnce.Do(func() { go ce.updateClientEntryLoop(cancellabelCtx, ce.done) }) } } } @@ -224,7 +218,7 @@ func (ce *Client) Close() error { if ce == nil { return nil } - + var err error ce.once.Do(func() { close(ce.done) @@ -241,11 +235,10 @@ func (ce *Client) Close() error { ce.sessions = make(map[cipher.PubKey]*SessionCommon) ce.log.Info("All sessions closed.") ce.sessionsMx.Unlock() - ce.porter.CloseAll(ce.log) + err = ce.EntityCommon.delClientEntry(context.Background()) }) - - return nil + return err } // Listen listens on a given dmsg port. diff --git a/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go b/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go index 02d0490845..6fbaa75e56 100644 --- a/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go +++ b/vendor/github.com/skycoin/dmsg/cmdutil/service_flags.go @@ -32,7 +32,6 @@ const ( // ServiceFlags represents common flags which are shared across services. type ServiceFlags struct { MetricsAddr string - HTTPAddr string Syslog string SyslogNet string LogLevel string @@ -77,7 +76,6 @@ func (sf *ServiceFlags) Init(rootCmd *cobra.Command, defaultTag, defaultConf str // flags rootCmd.Flags().StringVarP(&sf.MetricsAddr, "metrics", "m", sf.MetricsAddr, "address to serve metrics API from") - rootCmd.Flags().StringVarP(&sf.HTTPAddr, "http", "p", ":8082", "address to serve http API for health endpoint") rootCmd.Flags().StringVar(&sf.Syslog, "syslog", sf.Syslog, "address in which to dial to syslog server") rootCmd.Flags().StringVar(&sf.SyslogNet, "syslog-net", sf.SyslogNet, "network in which to dial to syslog server") rootCmd.Flags().StringVar(&sf.LogLevel, "syslog-lvl", sf.LogLevel, "minimum log level to report") diff --git a/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go b/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go index 56291a4822..a8b119e08c 100644 --- a/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go +++ b/vendor/github.com/skycoin/dmsg/cmdutil/signal_context.go @@ -16,7 +16,7 @@ func SignalContext(ctx context.Context, log logrus.FieldLogger) (context.Context ctx, cancel := context.WithCancel(ctx) - ch := make(chan os.Signal) + ch := make(chan os.Signal, 1) listenSigs := listenSignals() signal.Notify(ch, listenSigs...) diff --git a/vendor/github.com/skycoin/dmsg/disc/client.go b/vendor/github.com/skycoin/dmsg/disc/client.go index ba1fa19abe..d85dd1c1b3 100644 --- a/vendor/github.com/skycoin/dmsg/disc/client.go +++ b/vendor/github.com/skycoin/dmsg/disc/client.go @@ -25,6 +25,7 @@ type APIClient interface { Entry(context.Context, cipher.PubKey) (*Entry, error) PostEntry(context.Context, *Entry) error PutEntry(context.Context, cipher.SecKey, *Entry) error + DelEntry(context.Context, *Entry) error AvailableServers(context.Context) ([]*Entry, error) } @@ -106,9 +107,61 @@ func (c *httpClient) PostEntry(ctx context.Context, e *Entry) error { req.Header.Set("Content-Type", "application/json") - // Since v0.3.0 visors send ?timeout=true, before v0.3.0 do not. q := req.URL.Query() - q.Add("timeout", "true") + req.URL.RawQuery = q.Encode() + + req = req.WithContext(ctx) + + resp, err := c.client.Do(req) + if resp != nil { + defer func() { + if err := resp.Body.Close(); err != nil { + log.WithError(err).Warn("Failed to close response body.") + } + }() + } + if err != nil { + log.WithError(err).Error("Failed to perform request.") + return err + } + + if resp.StatusCode != http.StatusOK { + var httpResponse HTTPMessage + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + err = json.Unmarshal(bodyBytes, &httpResponse) + if err != nil { + return err + } + log.WithField("resp_body", httpResponse.Message). + WithField("resp_status", resp.StatusCode). + Error() + return errFromString(httpResponse.Message) + } + return nil +} + +// DelEntry deletes an Entry. +func (c *httpClient) DelEntry(ctx context.Context, e *Entry) error { + endpoint := c.address + "/dmsg-discovery/entry" + log := log.WithField("endpoint", endpoint) + + marshaledEntry, err := json.Marshal(e) + if err != nil { + return err + } + + req, err := http.NewRequest(http.MethodDelete, endpoint, bytes.NewBuffer(marshaledEntry)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + q := req.URL.Query() req.URL.RawQuery = q.Encode() req = req.WithContext(ctx) diff --git a/vendor/github.com/skycoin/dmsg/disc/http_message.go b/vendor/github.com/skycoin/dmsg/disc/http_message.go index 7336bf6973..30c7aa6ed1 100644 --- a/vendor/github.com/skycoin/dmsg/disc/http_message.go +++ b/vendor/github.com/skycoin/dmsg/disc/http_message.go @@ -9,6 +9,7 @@ import ( var ( MsgEntrySet = HTTPMessage{Code: http.StatusOK, Message: "wrote a new entry"} MsgEntryUpdated = HTTPMessage{Code: http.StatusOK, Message: "wrote new entry iteration"} + MsgEntryDeleted = HTTPMessage{Code: http.StatusOK, Message: "deleted entry"} ) // HTTPMessage represents a message to be returned as an http response diff --git a/vendor/github.com/skycoin/dmsg/disc/testing.go b/vendor/github.com/skycoin/dmsg/disc/testing.go index a697319edc..9fc87fe277 100644 --- a/vendor/github.com/skycoin/dmsg/disc/testing.go +++ b/vendor/github.com/skycoin/dmsg/disc/testing.go @@ -35,6 +35,12 @@ func (m *mockClient) entry(pk cipher.PubKey) (Entry, bool) { return e, ok } +func (m *mockClient) delEntry(pk cipher.PubKey) { + m.mx.Lock() + defer m.mx.Unlock() + delete(m.entries, pk) +} + func (m *mockClient) setEntry(entry Entry) { m.mx.Lock() defer m.mx.Unlock() @@ -87,6 +93,12 @@ func (m *mockClient) PostEntry(_ context.Context, entry *Entry) error { return nil } +// DelEntry returns the mock client static public key associated entry +func (m *mockClient) DelEntry(_ context.Context, entry *Entry) error { + m.delEntry(entry.Static) + return nil +} + // PutEntry updates a previously set entry func (m *mockClient) PutEntry(ctx context.Context, sk cipher.SecKey, e *Entry) error { e.Sequence++ diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go index c2d7e01756..ac71769a63 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli.go @@ -6,13 +6,9 @@ import ( "io" "net" "os" - "os/signal" - "syscall" - "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" - terminal "golang.org/x/term" "github.com/skycoin/dmsg/cipher" ) @@ -29,7 +25,7 @@ func DefaultCLI() CLI { return CLI{ Log: logging.MustGetLogger("dmsgpty-cli"), Net: DefaultCLINet, - Addr: DefaultCLIAddr, + Addr: DefaultCLIAddr(), } } @@ -95,7 +91,7 @@ func (cli *CLI) prepareConn() (net.Conn, error) { cli.Net = DefaultCLINet } if cli.Addr == "" { - cli.Addr = DefaultCLIAddr + cli.Addr = DefaultCLIAddr() } cli.Log. @@ -109,26 +105,6 @@ func (cli *CLI) prepareConn() (net.Conn, error) { return conn, nil } -// prepareStdin sets stdin to raw mode and provides a function to restore the original state. -func (cli *CLI) prepareStdin() (restore func(), err error) { - var oldState *terminal.State - if oldState, err = terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { - cli.Log. - WithError(err). - Warn("Failed to set stdin to raw mode.") - return - } - restore = func() { - // Attempt to restore state. - if err := terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { - cli.Log. - WithError(err). - Error("Failed to restore original stdin state.") - } - } - return -} - // servePty serves a pty connection via the dmsgpty-host. func (cli *CLI) servePty(ctx context.Context, ptyC *PtyClient, cmd string, args []string) error { ctx, cancel := context.WithCancel(ctx) @@ -167,28 +143,3 @@ func (cli *CLI) servePty(ctx context.Context, ptyC *PtyClient, cmd string, args return nil } - -// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. -func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { - ch := make(chan os.Signal, 1) - signal.Notify(ch, syscall.SIGWINCH) - for { - select { - case <-ctx.Done(): - return nil - case <-ch: - winSize, err := getPtySize(os.Stdin) - if err != nil { - return fmt.Errorf("failed to obtain window size: %v", err) - } - if err := ptyC.SetPtySize(winSize); err != nil { - return fmt.Errorf("failed to set remote window size: %v", err) - } - } - } -} - -// getPtySize obtains the size of the local terminal. -func getPtySize(t *os.File) (*pty.Winsize, error) { - return pty.GetsizeFull(t) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go new file mode 100644 index 0000000000..b5b3277d65 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_unix.go @@ -0,0 +1,63 @@ +//+build !windows + +package dmsgpty + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + + "github.com/creack/pty" + "golang.org/x/crypto/ssh/terminal" +) + +// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. +func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGWINCH) + for { + select { + case <-ctx.Done(): + return nil + case <-ch: + winSize, err := getPtySize(os.Stdin) + if err != nil { + return fmt.Errorf("failed to obtain window size: %v", err) + } + ws, err := NewWinSize(winSize) + if err != nil { + return fmt.Errorf("failed to convert pty size to WinSize: %v", err) + } + if err := ptyC.SetPtySize(ws); err != nil { + return fmt.Errorf("failed to set remote window size: %v", err) + } + } + } +} + +// getPtySize obtains the size of the local terminal. +func getPtySize(t *os.File) (*pty.Winsize, error) { + return pty.GetsizeFull(t) +} + +// prepareStdin sets stdin to raw mode and provides a function to restore the original state. +func (cli *CLI) prepareStdin() (restore func(), err error) { + var oldState *terminal.State + if oldState, err = terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { + cli.Log. + WithError(err). + Warn("Failed to set stdin to raw mode.") + return + } + restore = func() { + // Attempt to restore state. + if err = terminal.Restore(int(os.Stdin.Fd()), oldState); err != nil { + cli.Log. + WithError(err). + Error("Failed to restore original stdin state.") + } + } + return +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go new file mode 100644 index 0000000000..01938d0cca --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/cli_windows.go @@ -0,0 +1,44 @@ +//+build windows + +package dmsgpty + +import ( + "context" + "sync" + "time" + + "github.com/ActiveState/termtest/conpty" +) + +// ptyResizeLoop informs the remote of changes to the local CLI terminal window size. +func ptyResizeLoop(ctx context.Context, ptyC *PtyClient) error { + t := time.NewTicker(1 * time.Second) + mu := sync.RWMutex{} + var initialSize *WinSize + for { + select { + case <-ctx.Done(): + t.Stop() + return nil + case <-t.C: + mu.Lock() + size, err := getSize() + if err == nil { + if initialSize == nil { + initialSize = size + } else if initialSize.X != size.X || initialSize.Y != size.Y { + initialSize = size + if err = ptyC.SetPtySize(initialSize); err != nil { + mu.Unlock() + return err + } + } + } + mu.Unlock() + } + } +} + +func (cli *CLI) prepareStdin() (restore func(), err error) { + return conpty.InitTerminal(true) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go b/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go index 84f2a7a2d5..03ded6f813 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/conf.go @@ -3,6 +3,9 @@ package dmsgpty import ( "fmt" "os" + "path/filepath" + "runtime" + "strings" "github.com/skycoin/dmsg" ) @@ -26,7 +29,7 @@ func DefaultConfig() Config { DmsgSessions: dmsg.DefaultMinSessions, DmsgPort: DefaultPort, CLINet: DefaultCLINet, - CLIAddr: DefaultCLIAddr, + CLIAddr: DefaultCLIAddr(), } } @@ -40,3 +43,50 @@ func WriteConfig(conf Config, path string) error { enc.SetIndent("", " ") return enc.Encode(&conf) } + +func findStringsEnclosedBy(str string, sep string, result []string, lastIndex int) ([]string, int) { + s := strings.Index(str, sep) + if s == -1 { + return result, lastIndex + } + newS := str[s+len(sep):] + e := strings.Index(newS, sep) + if e == -1 { + lastIndex += len(sep) + return result, lastIndex + } + res := newS[:e] + if res != "" { + result = append(result, res) + } + last := s + len(res) + len(sep) + if lastIndex == -1 { + lastIndex = last + } else { + lastIndex += last + } + str = str[last:] + return findStringsEnclosedBy(str, sep, result, lastIndex) +} + +// ParseWindowsEnv finds '%'-enclosed windows env in json string +func ParseWindowsEnv(cliAddr string) string { + if runtime.GOOS == "windows" { + var res []string + results, lastIndex := findStringsEnclosedBy(cliAddr, "%", res, -1) + if len(results) > 0 { + paths := make([]string, len(results)+1) + for i, s := range results { + pth := os.Getenv(strings.ToUpper(s)) + if pth != "" { + paths[i] = pth + } + } + paths[len(paths)-1] = strings.Replace(cliAddr[lastIndex:], string(filepath.Separator), "", 1) + cliAddr = filepath.Join(paths...) + _ = strings.ReplaceAll(cliAddr, `\`, `\\`) + return cliAddr + } + } + return cliAddr +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const.go index 74bec2933d..4497d75379 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/const.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const.go @@ -12,15 +12,3 @@ const ( WhitelistRPCName = "whitelist" WhitelistURI = "dmsgpty/whitelist" ) - -// Constants related to CLI. -const ( - DefaultCLINet = "unix" - DefaultCLIAddr = "/tmp/dmsgpty.sock" -) - -// Constants related to dmsg. -const ( - DefaultPort = uint16(22) - DefaultCmd = "/bin/bash" -) diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go new file mode 100644 index 0000000000..8616378c7e --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const_unix.go @@ -0,0 +1,24 @@ +//+build !windows + +package dmsgpty + +import ( + "os" + "path/filepath" +) + +// Constants related to CLI. +const ( + DefaultCLINet = "unix" +) + +// Constants related to dmsg. +const ( + DefaultPort = uint16(22) + DefaultCmd = "/bin/bash" +) + +// DefaultCLIAddr gets the default cli address (temp address) +func DefaultCLIAddr() string { + return filepath.Join(os.TempDir(), "dmsgpty.sock") +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go new file mode 100644 index 0000000000..6b5ce832e7 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/const_windows.go @@ -0,0 +1,27 @@ +//+build windows + +package dmsgpty + +import ( + "os" + "path/filepath" +) + +const ( + DefaultCLINet = "unix" +) + +// Constants related to dmsg. +const ( + DefaultPort = uint16(22) + DefaultCmd = `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` +) + +// DefaultCLIAddr gets the default cli address +func DefaultCLIAddr() string { + homedir, err := os.UserHomeDir() + if err != nil { + homedir = os.TempDir() + } + return filepath.Join(homedir, "dmsgpty.sock") +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/host.go b/vendor/github.com/skycoin/dmsg/dmsgpty/host.go index 98b6bc00a7..51f1df01f9 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/host.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/host.go @@ -46,7 +46,7 @@ func (h *Host) ServeCLI(ctx context.Context, lis net.Listener) error { _ = lis.Close() //nolint:errcheck }() - log := logging.MustGetLogger("dmsgpty:cli-server") + log := logging.MustGetLogger("dmsg_pty:cli-server") mux := cliEndpoints(h) @@ -86,9 +86,11 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { return err } + log := logging.MustGetLogger("dmsg_pty") + go func() { <-ctx.Done() - h.log(). + log. WithError(lis.Close()). Info("Serve() ended.") }() @@ -96,7 +98,7 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { for { stream, err := lis.AcceptStream() if err != nil { - log := h.log().WithError(err) + log := log.WithError(err) if err, ok := err.(net.Error); ok && err.Temporary() { log.Warn("Failed to accept dmsg.Stream with temporary error, continuing...") continue @@ -111,7 +113,7 @@ func (h *Host) ListenAndServe(ctx context.Context, port uint16) error { } rPK := stream.RawRemoteAddr().PK - log := h.log().WithField("remote_pk", rPK.String()) + log := log.WithField("remote_pk", rPK.String()) log.Info("Processing dmsg.Stream...") if !h.authorize(log, rPK) { diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go index af94e5d9df..92deb1abfa 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client.go @@ -4,10 +4,8 @@ import ( "fmt" "io" "net/rpc" - "os" "sync" - "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" @@ -72,21 +70,6 @@ func (sc *PtyClient) close() (closed bool) { return closed } -// Start starts the pty. -func (sc *PtyClient) Start(name string, arg ...string) error { - size, err := pty.GetsizeFull(os.Stdin) - if err != nil { - sc.log.WithError(err).Warn("failed to obtain terminal size") - size = nil - } - return sc.StartWithSize(name, arg, size) -} - -// StartWithSize starts the pty with a specified size. -func (sc *PtyClient) StartWithSize(name string, arg []string, size *pty.Winsize) error { - return sc.call("Start", &CommandReq{Name: name, Arg: arg, Size: size}, &empty) -} - // Stop stops the pty. func (sc *PtyClient) Stop() error { return sc.call("Stop", &empty, &empty) @@ -107,11 +90,6 @@ func (sc *PtyClient) Write(b []byte) (int, error) { return n, processRPCError(err) } -// SetPtySize sets the pty size. -func (sc *PtyClient) SetPtySize(size *pty.Winsize) error { - return sc.call("SetPtySize", size, &empty) -} - func (*PtyClient) rpcMethod(m string) string { return PtyRPCName + "." + m } @@ -125,3 +103,22 @@ func (sc *PtyClient) call(method string, args, reply interface{}) error { return call.Error } } + +// Start starts the pty. +func (sc *PtyClient) Start(name string, arg ...string) error { + return sc.call("Start", &CommandReq{ + Name: name, + Arg: arg, + Size: nil, + }, &empty) +} + +// StartWithSize starts the pty with a specified size. +func (sc *PtyClient) StartWithSize(name string, arg []string, c *WinSize) error { + return sc.call("Start", &CommandReq{Name: name, Arg: arg, Size: c}, &empty) +} + +// SetPtySize sets the pty size. +func (sc *PtyClient) SetPtySize(size *WinSize) error { + return sc.call("SetPtySize", size, &empty) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go new file mode 100644 index 0000000000..36965a440d --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_client_windows.go @@ -0,0 +1,31 @@ +//+build windows + +package dmsgpty + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +// getSize gets windows terminal size +func getSize() (*WinSize, error) { + var bufInfo windows.ConsoleScreenBufferInfo + c, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) + if err != nil { + return nil, err + } + if err = windows.GetConsoleScreenBufferInfo(c, &bufInfo); err != nil { + if errors.Is(err, windows.ERROR_INVALID_HANDLE) { + return &WinSize{ + X: 80, + Y: 30, + }, nil + } + return nil, err + } + return NewWinSize(&windows.Coord{ + X: bufInfo.Window.Right - bufInfo.Window.Left + 1, + Y: bufInfo.Window.Bottom - bufInfo.Window.Top + 1, + }) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go index abb0508ec5..cf6aab8801 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway.go @@ -1,8 +1,12 @@ package dmsgpty -import ( - "github.com/creack/pty" -) +// WinSize wraps around pty.Winsize and *windows.Coord +type WinSize struct { + X uint16 + Y uint16 + Rows uint16 + Cols uint16 +} // PtyGateway represents a pty gateway, hosted by the pty.SessionServer type PtyGateway interface { @@ -10,7 +14,14 @@ type PtyGateway interface { Stop(_, _ *struct{}) error Read(reqN *int, respB *[]byte) error Write(reqB *[]byte, respN *int) error - SetPtySize(size *pty.Winsize, _ *struct{}) error + SetPtySize(size *WinSize, _ *struct{}) error +} + +// CommandReq represents a pty command. +type CommandReq struct { + Name string + Arg []string + Size *WinSize } // LocalPtyGateway is the gateway to a local pty. @@ -23,18 +34,6 @@ func NewPtyGateway(ses *Pty) PtyGateway { return &LocalPtyGateway{ses: ses} } -// CommandReq represents a pty command. -type CommandReq struct { - Name string - Arg []string - Size *pty.Winsize -} - -// Start starts the local pty. -func (g *LocalPtyGateway) Start(req *CommandReq, _ *struct{}) error { - return g.ses.Start(req.Name, req.Arg, req.Size) -} - // Stop stops the local pty. func (g *LocalPtyGateway) Stop(_, _ *struct{}) error { return g.ses.Stop() @@ -48,6 +47,11 @@ func (g *LocalPtyGateway) Read(reqN *int, respB *[]byte) error { return err } +// Start starts the local pty. +func (g *LocalPtyGateway) Start(req *CommandReq, _ *struct{}) error { + return g.ses.Start(req.Name, req.Arg, req.Size) +} + // Write writes to the local pty. func (g *LocalPtyGateway) Write(wb *[]byte, n *int) error { var err error @@ -56,10 +60,15 @@ func (g *LocalPtyGateway) Write(wb *[]byte, n *int) error { } // SetPtySize sets the local pty's window size. -func (g *LocalPtyGateway) SetPtySize(size *pty.Winsize, _ *struct{}) error { +func (g *LocalPtyGateway) SetPtySize(size *WinSize, _ *struct{}) error { return g.ses.SetPtySize(size) } +// SetPtySize sets the remote pty's window size. +func (g *ProxiedPtyGateway) SetPtySize(size *WinSize, _ *struct{}) error { + return g.ptyC.SetPtySize(size) +} + // ProxiedPtyGateway is an RPC gateway for a remote pty. type ProxiedPtyGateway struct { ptyC *PtyClient @@ -94,8 +103,3 @@ func (g *ProxiedPtyGateway) Write(reqB *[]byte, respN *int) error { *respN, err = g.ptyC.Write(*reqB) return err } - -// SetPtySize sets the remote pty's window size. -func (g *ProxiedPtyGateway) SetPtySize(size *pty.Winsize, _ *struct{}) error { - return g.ptyC.SetPtySize(size) -} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go new file mode 100644 index 0000000000..4176d90448 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_unix.go @@ -0,0 +1,32 @@ +//+build !windows + +package dmsgpty + +import ( + "errors" + + "github.com/creack/pty" +) + +// NewWinSize creates a new WinSize wrapper object +func NewWinSize(w *pty.Winsize) (*WinSize, error) { + if w == nil { + return nil, errors.New("pty size cannot be nil") + } + return &WinSize{ + X: w.X, + Y: w.Y, + Rows: w.Rows, + Cols: w.Cols, + }, nil +} + +// PtySize returns *pty.Winsize +func (w *WinSize) PtySize() *pty.Winsize { + return &pty.Winsize{ + Rows: w.Rows, + Cols: w.Cols, + X: w.X, + Y: w.Y, + } +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go new file mode 100644 index 0000000000..199c01b3ee --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_gateway_windows.go @@ -0,0 +1,28 @@ +//+build windows + +package dmsgpty + +import ( + "errors" + + "golang.org/x/sys/windows" +) + +// NewWinSize creates a new WinSize object +func NewWinSize(w *windows.Coord) (*WinSize, error) { + if w == nil { + return nil, errors.New("pty size is nil") + } + return &WinSize{ + X: uint16(w.X), + Y: uint16(w.Y), + }, nil +} + +// PtySize returns *windows.Coord object +func (w *WinSize) PtySize() *windows.Coord { + return &windows.Coord{ + X: int16(w.X), + Y: int16(w.Y), + } +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go similarity index 80% rename from vendor/github.com/skycoin/dmsg/dmsgpty/pty.go rename to vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go index 2122a00800..b7dc14d122 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/pty.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_unix.go @@ -1,3 +1,5 @@ +//+build !windows + package dmsgpty import ( @@ -26,27 +28,6 @@ func NewPty() *Pty { return new(Pty) } -// Start runs a command with the given command name, args and optional window size. -func (s *Pty) Start(name string, args []string, size *pty.Winsize) error { - s.mx.Lock() - defer s.mx.Unlock() - - if s.pty != nil { - return ErrPtyAlreadyRunning - } - - cmd := exec.Command(name, args...) //nolint:gosec - cmd.Env = os.Environ() - - f, err := pty.StartWithSize(cmd, size) //nolint:gosec - if err != nil { - return err - } - - s.pty = f - return nil -} - // Stop stops the running command and closes the pty. func (s *Pty) Stop() error { s.mx.Lock() @@ -85,8 +66,37 @@ func (s *Pty) Write(b []byte) (int, error) { return s.pty.Write(b) } +// Start runs a command with the given command name, args and optional window size. +func (s *Pty) Start(name string, args []string, size *WinSize) error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty != nil { + return ErrPtyAlreadyRunning + } + + cmd := exec.Command(name, args...) //nolint:gosec + cmd.Env = os.Environ() + var sz *pty.Winsize + var err error + + if size == nil { + sz = nil + } else { + sz = size.PtySize() + } + + f, err := pty.StartWithSize(cmd, sz) //nolint:gosec + if err != nil { + return err + } + + s.pty = f + return nil +} + // SetPtySize sets the pty size. -func (s *Pty) SetPtySize(size *pty.Winsize) error { +func (s *Pty) SetPtySize(size *WinSize) error { s.mx.RLock() defer s.mx.RUnlock() @@ -94,5 +104,7 @@ func (s *Pty) SetPtySize(size *pty.Winsize) error { return ErrPtyNotRunning } - return pty.Setsize(s.pty, size) + sz := size.PtySize() + + return pty.Setsize(s.pty, sz) } diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go new file mode 100644 index 0000000000..f19f5bb4f2 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/pty_windows.go @@ -0,0 +1,125 @@ +//+build windows + +package dmsgpty + +import ( + "errors" + "fmt" + "os" + "sync" + "syscall" + + "github.com/ActiveState/termtest/conpty" +) + +// Pty errors. +var ( + ErrPtyAlreadyRunning = errors.New("a pty session is already running") + ErrPtyNotRunning = errors.New("no active pty session") +) + +// Pty runs a local pty. +type Pty struct { + pty *conpty.ConPty + mx sync.RWMutex +} + +// NewPty creates a new Pty. +func NewPty() *Pty { + return new(Pty) +} + +// Stop stops the running command and closes the pty. +func (s *Pty) Stop() error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty == nil { + return ErrPtyNotRunning + } + + err := s.pty.Close() + s.pty = nil + return err +} + +// Read reads any stdout or stderr outputs from the pty. +func (s *Pty) Read(b []byte) (int, error) { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.pty == nil { + return 0, ErrPtyNotRunning + } + + return s.pty.OutPipe().Read(b) +} + +// Write writes to the stdin of the pty. +func (s *Pty) Write(b []byte) (int, error) { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.pty == nil { + return 0, ErrPtyNotRunning + } + + res, err := s.pty.Write(b) + return int(res), err +} + +// Start runs a command with the given command name, args and optional window size. +func (s *Pty) Start(name string, args []string, size *WinSize) error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.pty != nil { + return ErrPtyAlreadyRunning + } + + var err error + + if size == nil { + size, err = getSize() + if err != nil { + return err + } + + } + fmt.Printf("Size of term: X=>%d, Y=>%d\n", size.X, size.Y) + pty, err := conpty.New( + int16(size.X), int16(size.Y), + ) + if err != nil { + return err + } + + pid, _, err := pty.Spawn( + name, + args, + &syscall.ProcAttr{ + Env: os.Environ(), + }, + ) + + if err != nil { + return err + } + + fmt.Printf("starting process with pid %d \n", pid) + + s.pty = pty + return nil +} + +// SetPtySize sets the pty size. +func (s *Pty) SetPtySize(size *WinSize) error { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.pty == nil { + return ErrPtyNotRunning + } + + return s.pty.Resize(uint16(size.X), uint16(size.Y)) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go index bf1b5d4a15..b75d52c434 100644 --- a/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui.go @@ -10,7 +10,6 @@ import ( "sync/atomic" "time" - "github.com/creack/pty" "github.com/sirupsen/logrus" "github.com/skycoin/skycoin/src/util/logging" "nhooyr.io/websocket" @@ -32,7 +31,7 @@ type UIConfig struct { // DefaultUIConfig returns the default UI config. func DefaultUIConfig() UIConfig { return UIConfig{ - CmdName: "/bin/bash", + CmdName: DefaultCmd, CmdArgs: nil, } } @@ -155,7 +154,7 @@ func (ui *UI) Handler() http.HandlerFunc { } defer func() { log.WithError(ptyC.Close()).Debug("Closed ptyC.") }() - if err := ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, &pty.Winsize{Rows: wsRows, Cols: wsCols}); err != nil { + if err = ui.uiStartSize(ptyC); err != nil { log.Print("xxxx") writeWSError(log, wsConn, err) diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go new file mode 100644 index 0000000000..4047d058b1 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_unix.go @@ -0,0 +1,15 @@ +//+build !windows + +package dmsgpty + +import ( + "github.com/creack/pty" +) + +func (ui *UI) uiStartSize(ptyC *PtyClient) error { + winSize, err := NewWinSize(&pty.Winsize{Rows: wsRows, Cols: wsCols}) + if err != nil { + return err + } + return ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, winSize) +} diff --git a/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go new file mode 100644 index 0000000000..b8905dc5e6 --- /dev/null +++ b/vendor/github.com/skycoin/dmsg/dmsgpty/ui_windows.go @@ -0,0 +1,16 @@ +//+build windows + +package dmsgpty + +import "golang.org/x/sys/windows" + +func (ui *UI) uiStartSize(ptyC *PtyClient) error { + ws, err := NewWinSize(&windows.Coord{ + X: wsCols, + Y: wsRows, + }) + if err != nil { + return err + } + return ptyC.StartWithSize(ui.conf.CmdName, ui.conf.CmdArgs, ws) +} diff --git a/vendor/github.com/skycoin/dmsg/entity_common.go b/vendor/github.com/skycoin/dmsg/entity_common.go index a790b04e6e..7798601608 100644 --- a/vendor/github.com/skycoin/dmsg/entity_common.go +++ b/vendor/github.com/skycoin/dmsg/entity_common.go @@ -30,8 +30,8 @@ type EntityCommon struct { log logrus.FieldLogger - setSessionCallback func(ctx context.Context, sessionCount int) error - delSessionCallback func(ctx context.Context, sessionCount int) error + setSessionCallback func(ctx context.Context) error + delSessionCallback func(ctx context.Context) error } func (c *EntityCommon) init(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, log logrus.FieldLogger, updateInterval time.Duration) { @@ -107,7 +107,7 @@ func (c *EntityCommon) setSession(ctx context.Context, dSes *SessionCommon) bool c.sessions[dSes.RemotePK()] = dSes if c.setSessionCallback != nil { - if err := c.setSessionCallback(ctx, len(c.sessions)); err != nil { + if err := c.setSessionCallback(ctx); err != nil { c.log. WithField("func", "EntityCommon.setSession"). WithError(err). @@ -121,7 +121,7 @@ func (c *EntityCommon) delSession(ctx context.Context, pk cipher.PubKey) { c.sessionsMx.Lock() delete(c.sessions, pk) if c.delSessionCallback != nil { - if err := c.delSessionCallback(ctx, len(c.sessions)); err != nil { + if err := c.delSessionCallback(ctx); err != nil { c.log. WithField("func", "EntityCommon.delSession"). WithError(err). @@ -237,46 +237,26 @@ func (c *EntityCommon) updateClientEntry(ctx context.Context, done chan struct{} return c.dc.PostEntry(ctx, entry) } - // Whether the client's CURRENT delegated servers is the same as what would be advertised. - sameSrvPKs := cipher.SamePubKeys(srvPKs, entry.Client.DelegatedServers) - - // No update is needed if delegated servers has no delta, and an entry update is not due. - if _, due := c.updateIsDue(); sameSrvPKs && !due { - return nil - } - entry.Client.DelegatedServers = srvPKs c.log.WithField("entry", entry).Debug("Updating entry.") return c.dc.PutEntry(ctx, c.sk, entry) } -func (c *EntityCommon) updateClientEntryLoop(ctx context.Context, done chan struct{}) { - t := time.NewTimer(c.updateInterval) - defer t.Stop() - - for { - select { - case <-ctx.Done(): - return - - case <-t.C: - if lastUpdate, due := c.updateIsDue(); !due { - t.Reset(c.updateInterval - time.Since(lastUpdate)) - continue - } +func (c *EntityCommon) delClientEntry(ctx context.Context) (err error) { - c.sessionsMx.Lock() - err := c.updateClientEntry(ctx, done) - c.sessionsMx.Unlock() - - if err != nil { - c.log.WithError(err).Warn("Failed to update discovery entry.") - } + entry, err := c.dc.Entry(ctx, c.pk) + if err != nil { + return err + } - // Ensure we trigger another update within given 'updateInterval'. - t.Reset(c.updateInterval) + defer func() { + if err == nil { + c.log.Debug("Entry Deleted successfully.") } - } + }() + + c.log.WithField("entry", entry).Debug("Deleting entry.") + return c.dc.DelEntry(ctx, entry) } func getServerEntry(ctx context.Context, dc disc.APIClient, srvPK cipher.PubKey) (*disc.Entry, error) { diff --git a/vendor/github.com/skycoin/dmsg/go.mod b/vendor/github.com/skycoin/dmsg/go.mod index 8c834f956c..752b85fcc9 100644 --- a/vendor/github.com/skycoin/dmsg/go.mod +++ b/vendor/github.com/skycoin/dmsg/go.mod @@ -3,6 +3,7 @@ module github.com/skycoin/dmsg go 1.16 require ( + github.com/ActiveState/termtest/conpty v0.5.0 github.com/VictoriaMetrics/metrics v1.12.3 github.com/creack/pty v1.1.10 github.com/go-chi/chi v4.1.2+incompatible @@ -24,9 +25,10 @@ require ( github.com/skycoin/yamux v0.0.0-20200803175205-571ceb89da9f github.com/spf13/cobra v0.0.5 github.com/stretchr/testify v1.4.0 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb - golang.org/x/sys v0.0.0-20210112080510-489259a85091 - golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c + golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect nhooyr.io/websocket v1.8.2 ) diff --git a/vendor/github.com/skycoin/dmsg/go.sum b/vendor/github.com/skycoin/dmsg/go.sum index ac9db4222f..a9c78bcebf 100644 --- a/vendor/github.com/skycoin/dmsg/go.sum +++ b/vendor/github.com/skycoin/dmsg/go.sum @@ -1,7 +1,13 @@ +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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I= github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -84,6 +90,8 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pires/go-proxyproto v0.3.3 h1:jOXGrsAfSQVFiD1hWg1aiHpLYsd6SJw/8cLN594sB7Q= github.com/pires/go-proxyproto v0.3.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -143,10 +151,13 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0= golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/skycoin/dmsg/server.go b/vendor/github.com/skycoin/dmsg/server.go index 7ecc88f84f..638d9d118e 100644 --- a/vendor/github.com/skycoin/dmsg/server.go +++ b/vendor/github.com/skycoin/dmsg/server.go @@ -67,10 +67,10 @@ func NewServer(pk cipher.PubKey, sk cipher.SecKey, dc disc.APIClient, conf *Serv s.done = make(chan struct{}) s.addrDone = make(chan struct{}) s.maxSessions = conf.MaxSessions - s.setSessionCallback = func(ctx context.Context, sessionCount int) error { + s.setSessionCallback = func(ctx context.Context) error { return s.updateServerEntry(ctx, s.AdvertisedAddr(), s.maxSessions) } - s.delSessionCallback = func(ctx context.Context, sessionCount int) error { + s.delSessionCallback = func(ctx context.Context) error { return s.updateServerEntry(ctx, s.AdvertisedAddr(), s.maxSessions) } return s diff --git a/vendor/modules.txt b/vendor/modules.txt index 3a033f2e10..4f38eaf6f6 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,6 +1,11 @@ +# github.com/ActiveState/termtest/conpty v0.5.0 +github.com/ActiveState/termtest/conpty # github.com/AudriusButkevicius/pfilter v0.0.0-20210515103320-4b4b86609d51 ## explicit github.com/AudriusButkevicius/pfilter +# github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 +github.com/Azure/go-ansiterm +github.com/Azure/go-ansiterm/winterm # github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d ## explicit github.com/StackExchange/wmi @@ -128,7 +133,7 @@ github.com/shirou/gopsutil/process ## explicit github.com/sirupsen/logrus github.com/sirupsen/logrus/hooks/syslog -# github.com/skycoin/dmsg v0.0.0-20210827120633-3d20b41d46a2 +# github.com/skycoin/dmsg v0.0.0-20210915195912-2f9b055f39fe ## explicit github.com/skycoin/dmsg github.com/skycoin/dmsg/buildinfo From 6a4d354ae3d4167c83f03162794855c6f75bd1fd Mon Sep 17 00:00:00 2001 From: ersonp Date: Thu, 16 Sep 2021 16:16:10 +0530 Subject: [PATCH 12/13] Disable appveyor windows test --- .appveyor.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 218e9b3ff7..3596182209 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,9 +11,9 @@ environment: - job_name: MacOS appveyor_build_worker_image: macos GOARCH: amd64 - - job_name: Windows - appveyor_build_worker_image: Visual Studio 2019 - GOARCH: amd64 + # - job_name: Windows + # appveyor_build_worker_image: Visual Studio 2019 + # GOARCH: amd64 # For release, by pushing tag - job_name: linux-amd64 @@ -31,9 +31,9 @@ environment: - job_name: darwin-amd64 appveyor_build_worker_image: macos GOARCH: amd64 - - job_name: windows-amd64 - appveyor_build_worker_image: Visual Studio 2019 - GOARCH: amd64 + # - job_name: windows-amd64 + # appveyor_build_worker_image: Visual Studio 2019 + # GOARCH: amd64 for: - # Linux and MacOS From 8ae4f3bdd04582e9fbb2ca5c504f33725e030bce Mon Sep 17 00:00:00 2001 From: ersonp Date: Thu, 16 Sep 2021 16:30:59 +0530 Subject: [PATCH 13/13] Update nodejs ver in appveyor --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3596182209..ff66e38fda 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,6 @@ version: "{build}" -stack: node 10.16.3 +stack: node 16.8.0 environment: matrix: