Giter Club home page Giter Club logo

gexpect's People

Contributors

alban avatar heyitsanthony avatar iaguis avatar jonboulle avatar krnowak avatar lucab avatar ppalucki avatar steveej avatar svendowideit avatar thomasrooney avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gexpect's Issues

Interact looks racy

Interact tries to copy everything from PTY to both standard output and standard error in two goroutines. Isn't that racy? Sometimes contents of PTY will end up in standard output, sometimes in standard error.

Not sure what should be the fix - either remove the go io.Copy(os.Stderr, expect.f) line or something like:

go func() {
    mw := io.MultiWriter(os.Stdout, os.Stderr)
    io.Copy(mw, expect.f)
}()

I suppose the former.

Input will also be printed

Hello @ThomasRooney

I tried your project and it's really nice but may be one problem is that each input line will be printed once as well. It looks like:

print('aaa')
pint('aaa')
raaa
print('bbb')
print('bbb')
bbb

Is it a problem or something I used incorrectly?

Best regards,
Marshall

WHen running a shell

I need to write an interactive shell using mysql. When I spawn mysql the mysql client launches beautifully and I am able to hide some commands to initialize the environment, however I loose the ability to go back through command history. WHen I hit any of the arrow keys I get strange characters.

`mysql> select user();
select user();
+----------------------+
| user() |
+----------------------+
| sduser@sdhost12 |
+----------------------+
1 row in set (0.00 sec)

mysql> ^[[A`

Can't compile with gollvm. Redefinition of 'main' , in ping.go

Hi.

$ go build -i -v -x
WORK=/tmp/go-build260147053
/home/oceanfish81/gexpect/examples
mkdir -p $WORK/b001/
cd $WORK
/home/oceanfish81/gollvm_dist/bin/llvm-goc -fgo-importcfg=/dev/null -c -x c - -o /dev/null || true
mkdir -p $WORK/b001/importcfgroot/github.com/ThomasRooney
ln -s /home/oceanfish81/go/pkg/gccgo_linux_amd64/github.com/ThomasRooney/libgexpect.a $WORK/b001/importcfgroot/github.com/ThomasRooney/libgexpect.a
cd /home/oceanfish81/gexpect/examples
/home/oceanfish81/gollvm_dist/bin/llvm-goc -c -O2 -g -m64 -fdebug-prefix-map=$WORK=/tmp/go-build -gno-record-gcc-switches -fgo-relative-import-path=
/home/oceanfish81/gexpect/examples -o $WORK/b001/go.o -I $WORK/b001/importcfgroot ./ftp.go ./ping.go ./python.go ./screen.go

_/home/oceanfish81/gexpect/examples

./ping.go:6:1: error: redefinition of 'main'
./ftp.go:6:1: note: previous definition of 'main' was here
./python.go:6:1: error: redefinition of 'main'
./ftp.go:6:1: note: previous definition of 'main' was here
./screen.go:7:1: error: redefinition of 'main'
./ftp.go:6:1: note: previous definition of 'main' was here

$ go version
go version go1.15.2 gollvm LLVM 12.0.0git linux/amd64

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/oceanfish81/.cache/go-build"
GOENV="/home/oceanfish81/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/oceanfish81/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/oceanfish81/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/oceanfish81/gollvm_dist"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/oceanfish81/gollvm_dist/tools"
GCCGO="/home/oceanfish81/gollvm_dist/bin/llvm-goc"
AR="ar"
CC="/usr/bin/clang"
CXX="/usr/bin/clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build393449434=/tmp/go-build -gno-record-gcc-switches -funwind-tables"

process pipe shouldn't be explicitly closed

b6b347c seems like a regression; when the child dies it loses the pty and the pipe will close automatically.

With the forced Close, the Interact goroutines seem to be delayed past the cmd.Wait():

Too many goroutines running after all test(s).
3 instances of:
syscall.Syscall(...)
    /usr/lib/go/src/syscall/asm_linux_amd64.s:18 +0x5
syscall.read(...)
    /usr/lib/go/src/syscall/zsyscall_linux_amd64.go:783 +0x5f
syscall.Read(...)
    /usr/lib/go/src/syscall/syscall_unix.go:161 +0x4d
os.(*File).read(...)
    /usr/lib/go/src/os/file_unix.go:228 +0x53
os.(*File).Read(...)
    /usr/lib/go/src/os/file.go:95 +0x8a
io.copyBuffer(...)
    /usr/lib/go/src/io/io.go:380 +0x247
io.Copy(...)
    /usr/lib/go/src/io/io.go:350 +0x64
created by github.com/coreos/etcd/vendor/github.com/thomasrooney/gexpect.(*ExpectSubprocess).Interact
    /home/anthony/go/src/github.com/coreos/etcd/vendor/github.com/thomasrooney/gexpect/gexpect.go:377 +0x145

Expect hangs with interactive command

Program hangs when I try to execute Expect with unexpected string

child, err := gexpect.Spawn("passwd test")
if err != nil {
	log.Fatal(err)
}
err = child.Expect("YOU WILL NEVER FIND ME")
if err != nil {
	log.Println("should print error", err)  // should print error, but it never execute
}

I want to do this because there could be different results for one command. For example, ssh $hostname ls /tmp may output the directory information of tmp directly if the ssh public key has copied to the host, or get the prompt for the password, I found it only works well with non-interactive command.

not able to read the output in case of some CLI console responses

this gexpect package worked better than the google and netflix ones. but I have one challenge.

I'm trying to capture the response from the automation that I'm trying to do using this package.. my script has ssh commands, and then runs a cli command which has its sub prompt. I'm able to grab all the screen text, using the Capture() and Collect() functions, except after reaching CLI's prompt.

However, when I use Interact() at the end of the script, and remove the Capture() and Collect() calls, then I'm able to see the text from the cli console. So, the gexpect is able to read the screen text from the CLI console, but i'm not able to grab them using the Capture() and Collect() functions. any suggestion on how to resolve this blocker?

Please let me know if you need any more details.

env: mac mojave

ReadLine() not working as expected

Hey @ThomasRooney,

Just hooked up your code to do run a router maintenance script.

I have noticed that when I call ReadLine() the output is empty. If I try ReadUntil('#') it does show the output up until that point.

Am I doing something wrong?

Thanks,

Jon

Code below;

package main

import (
    "fmt"
    "github.com/ThomasRooney/gexpect"
)

func main() {
    fmt.Printf("Starting SSH...\n")
    p, err := gexpect.Spawn("ssh [email protected]")
    if err != nil {
        panic(err)
    }
    p.Expect("Password:")
    p.SendLine("password123")
    p.Expect("#")
    p.Send("show version | include System image ")
    f, err := p.ReadLine()
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v\n", f) //Variable f is empty, If i replace with ReadUntil('#') it shows the string up to this point
    p.Close()
}

TestBiChannel failure

Using the current master of gexpect with Ubuntu 14.04 and Go 1.4.2 linux/amd64, running "go test -v" hangs inside TestBiChannel:

=== RUN TestHelloWorld
--- PASS: TestHelloWorld (0.00s)
        gexpect_test.go:10: Testing Hello World...
=== RUN TestDoubleHelloWorld
--- PASS: TestDoubleHelloWorld (0.00s)
        gexpect_test.go:22: Testing Double Hello World...
=== RUN TestHelloWorldFailureCase
--- PASS: TestHelloWorldFailureCase (0.00s)
        gexpect_test.go:42: Testing Hello World Failure case...
=== RUN TestBiChannel
(...never completes...)

Debugging a little, it seems that the "msg" variable at gexpect_test:62 gets the original "echo" twice and waiting for "echo2" never completes.

Is there a way to read more than one line?

Is there a easy way to read more that one line from the output ?

In the python version you can use the following to grab the whole buffer:

child.before

I'm looking for something similar.

or a way to search the buffer for a string and read it and everything else on the line .

docs: Wait() may deadlock if child buffer is not consumed

As per subject, Wait() may run into a subtle deadlock if the child buffer is not drained. Consider the following example:

package main

import "github.com/ThomasRooney/gexpect"
import "fmt"

func main() {
        fmt.Printf("Starting...\n")
        child, err := gexpect.Spawn("bash")
        if err != nil {
                panic(err)
        }
        child.Expect("$")
        fmt.Printf("Got prompt..\n")

        len := 8000
        child.SendLine(fmt.Sprintf("for i in `seq %d`; do echo 'a'; done", len))
        child.SendLine(`exit`)

        fmt.Printf("Waiting for exit...\n")
        child.Wait()

        fmt.Printf("Done\n")
        child.Close()
}

When running this, Wait() will never return. Lowering the len value, it will correctly return.

The problem with the example is that child output should be asynchronously drained while waiting, otherwise it can block when writing to the pty and deadlock with the parent (gexpect) as shown in strace:

$ strace -f -p ${BASH_PID}
write(1, "a\n", 2
$ strace -f -p ${GOEXPECT_PID}
waitid(P_PID, ${BASH_PID},  <unfinished ...>

This seems to be an intrinsic limitation of Wait(), and should be properly documented similarly to https://pexpect.readthedocs.io/en/stable/api/pexpect.html#pexpect.spawn.wait

AsyncInteractChannels

Hi,

I was testing "AsyncInteractChannels". When using:

send, receiver := child.AsyncInteractChannels()

Somehow the output looks buffered or waiting on lines '\n'. Would it be possible to create a version without buffering? So each character is passed without delay. Example code:

package main

import (
	"bufio"
	"fmt"
	"os"
	"time"

	"github.com/ThomasRooney/gexpect"
)

func main() {
	// open program
	child, err := gexpect.Spawn("/bin/sh")
	if err != nil {
		panic("could not open program " + err.Error())
	}
	defer child.Close()

	// open in/out channels
	doCommand, receiver := child.AsyncInteractChannels()
	doneChan := make(chan bool)
	tickChan := time.NewTicker(time.Millisecond * 10000).C

	// keyboard
	reader := bufio.NewReader(os.Stdin)
	keyboard := make(chan string)
	go func(keyboard chan string) {
		for {
			s, _, err := reader.ReadRune()
			if err != nil {
				close(keyboard)
				return
			}
			keyboard <- string(s)
		}
	}(keyboard)

	// the loop
	for {
		select {
		case msg, open := <-receiver:
			if !open {
				return
			}
			fmt.Printf("%s\n", msg)
		case <-tickChan:
			doCommand <- "echo example trigger 1000 seconds\n"
		case commandline := <-keyboard:
			doCommand <- commandline
		case <-doneChan:
			fmt.Println("Done")
			return
		}
	}
}

Regards, Arjen

Document ExpectTimeout()

Reading the documentation and the test cases led me to believe there was no handling for the case of a timeout. But then I looked at your actual code and you do use the time.After() inside a select go idiom for a timeout option. Why not provide an example in your read me, or provide a test case?

This looks iike a very promising project. I wrote a ton of expect a long time ago and now that I'm into go, having a go version of expect is great. Amazing how few lines of go it takes to make something so useful.

Also, why not make the timeout error a global constant so the user could test the error received against it to handle the normal timeout case more cleanly?

readLine() CR/LF issue

Hey there! 👋

I tried to use gexpect to test a CLI app and encountered an issue regarding expected and actual line endings (i.e. 0xa/0xd). On echo 'test\n' I was expecting to get test\n, but unfortunately I get test\r as a return value of the readLine function. If my target app outputs multiline go string with \n as a line separator, I simply can't use the same string as a test expectation since the concatenated result of the reading of all the lines will be separated with \rs.

Here is a minimal code sample to reproduce:

package main

import (
	"fmt"

	"github.com/ThomasRooney/gexpect"
)

func main() {
	child, err := gexpect.Spawn("echo 'test\n'")
	if err != nil {
		panic(err)
	}

	expected := "test\n"

	actual, _ := child.ReadLine()
	fmt.Println("Expected:")
	fmt.Printf("%#v", expected)
	fmt.Println()
	fmt.Printf("%#v", []byte(expected))
	fmt.Println("\n=========================")
	fmt.Println("Actual:")
	fmt.Printf("%#v", actual)
	fmt.Println()
	fmt.Printf("%#v", []byte(actual))
}

On my machine (MacOS Sierra 10.12.2, zsh 5.3, go 1.7.4 darwin/amd64) it results in:

Expected:
"test\n"
[]byte{0x74, 0x65, 0x73, 0x74, 0xa}
=========================
Actual:
"test\r"
[]byte{0x74, 0x65, 0x73, 0x74, 0xd}

If I change the test string in above code to test\r the result will be:

Expected:
"test\r"
[]byte{0x74, 0x65, 0x73, 0x74, 0xd}
=========================
Actual:
"test\r\r"
[]byte{0x74, 0x65, 0x73, 0x74, 0xd, 0xd}

windows ?

Anyone know if this behaves on Windows ? Good old windows has some differences for this type of stuff :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.