英文:
How to remove Cursor Position ANSI escape code from `HijackedResponse` in Go?
问题
我正在尝试使用Go执行(与)一个Docker容器进行交互。这是我正在使用的代码:
func (docker *Docker) redirectResponseToOutputStream(outputStream, errorStream io.Writer, resp io.Reader) error {
_, err := stdcopy.StdCopy(outputStream, errorStream, resp)
return err
}
func (docker *Docker) holdHijackedConnection(inputStream io.Reader, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
receiveStdout := make(chan error)
if outputStream != nil || errorStream != nil {
go func() {
receiveStdout <- docker.redirectResponseToOutputStream(outputStream, errorStream, resp.Reader)
}()
}
stdinDone := make(chan struct{})
go func() {
if inputStream != nil {
io.Copy(resp.Conn, inputStream)
}
resp.CloseWrite()
close(stdinDone)
}()
select {
case err := <-receiveStdout:
return err
case <-stdinDone:
if outputStream != nil || errorStream != nil {
return <-receiveStdout
}
}
return nil
}
...并在这里调用holdHijackedConnection
:
func (docker *Docker) ContainerExec(ctx context.Context, container *injection.Container) error {
createResponse, err := docker.client.ContainerExecCreate(ctx, container.ID, types.ExecConfig{
AttachStdout: true,
AttachStderr: true,
AttachStdin: true,
Detach: true,
Tty: true,
Cmd: []string{"sh"},
})
if err != nil {
return err
}
stream, err := docker.client.ContainerExecAttach(ctx, createResponse.ID, types.ExecStartCheck{})
if err != nil {
return err
}
defer stream.Close()
docker.holdHijackedConnection(os.Stdin, os.Stdout, os.Stderr, stream)
return nil
}
一些说明:
sh
是必需的,它是一个alpine镜像injection.Container
只是保存有关容器的信息,它是一个自定义结构体Docker
是一个结构体,保存着Docker客户端(来自github.com/docker/docker/client
的Client
实例)
如果我执行我的应用程序,从cli获得的结果是这样的:
/usr/app $ ^[[43;12R
据我所知,^[[43;12R是光标位置的ANSI转义代码。我可以执行命令,比如ls
或npm i
,但我总是得到这些ANSI转义代码。
我的问题是,有没有办法从stdout中删除这些代码?
英文:
I am trying to exec (interact with) a docker container, with Go.
This is the code I am using:
func (docker *Docker) redirectResponseToOutputStream(outputStream, errorStream io.Writer, resp io.Reader) error {
_, err := stdcopy.StdCopy(outputStream, errorStream, resp)
return err
}
func (docker *Docker) holdHijackedConnection(inputStream io.Reader, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
receiveStdout := make(chan error)
if outputStream != nil || errorStream != nil {
go func() {
receiveStdout <- docker.redirectResponseToOutputStream(outputStream, errorStream, resp.Reader)
}()
}
stdinDone := make(chan struct{})
go func() {
if inputStream != nil {
io.Copy(resp.Conn, inputStream)
}
resp.CloseWrite()
close(stdinDone)
}()
select {
case err := <-receiveStdout:
return err
case <-stdinDone:
if outputStream != nil || errorStream != nil {
return <-receiveStdout
}
}
return nil
}
...and call the the holdHijackedConnection
here:
func (docker *Docker) ContainerExec(ctx context.Context, container *injection.Container) error {
createResponse, err := docker.client.ContainerExecCreate(ctx, container.ID, types.ExecConfig{
AttachStdout: true,
AttachStderr: true,
AttachStdin: true,
Detach: true,
Tty: true,
Cmd: []string{"sh"},
})
if err != nil {
return err
}
stream, err := docker.client.ContainerExecAttach(ctx, createResponse.ID, types.ExecStartCheck{})
if err != nil {
return err
}
defer stream.Close()
docker.holdHijackedConnection(os.Stdin, os.Stdout, os.Stderr, stream)
return nil
}
Some notes:
sh
is necessary, it's an alpine imageinjection.Container
just holds information about the container, it's a custom structDocker
is a struct, that holds the docker client (an instance fromClient
at github.com/docker/docker/client)
What I get as a result to the cli, if I execute my application, is something like this:
/usr/app $ ^[[43;12R
I far as I know, the ^[[43;12R is the ANSI escape code for the position of the cursor.
I can execute commands, like ls
or npm i
whatever, but I alwasy get back these ANSI escape codes.
My question is, is there some way to remove these from the stdout?
答案1
得分: 1
我最终找到了答案。
问题是,我应该使用github.com/docker/cli/cli/command
包及其DockerCli
,而不是os.Std...
。通过以下方式,它可以为我管理输出、错误和输入流:
func (docker *Docker) holdHijackedConnection(resp types.HijackedResponse) error {
cli, _ := command.NewDockerCli()
outputStream := cli.Out()
errorStream := cli.Err()
inputStream := cli.In()
inputStream.SetRawTerminal()
defer inputStream.RestoreTerminal()
receiveStdout := make(chan error)
if outputStream != nil || errorStream != nil {
go func() {
receiveStdout <- docker.redirectResponseToOutputStream(outputStream, errorStream, resp.Reader)
}()
}
stdinDone := make(chan struct{})
go func() {
if inputStream != nil {
io.Copy(resp.Conn, inputStream)
}
resp.CloseWrite()
close(stdinDone)
}()
select {
case err := <-receiveStdout:
return err
case <-stdinDone:
if outputStream != nil || errorStream != nil {
return <-receiveStdout
}
}
return nil
}
如果你想要添加CTRL+C来退出,你应该在ContainerExecCreate
的ExecConfig
中设置DetachKeys
。否则,执行exit
将会分离它。
英文:
I eventually found out.
The problem was, that I should use the github.com/docker/cli/cli/command
package and its DockerCli
instead of os.Std...
. This can manage this for me, by setting the output, error and input stream like this:
func (docker *Docker) holdHijackedConnection(resp types.HijackedResponse) error {
cli, _ := command.NewDockerCli()
outputStream := cli.Out()
errorStream := cli.Err()
inputStream := cli.In()
inputStream.SetRawTerminal()
defer inputStream.RestoreTerminal()
receiveStdout := make(chan error)
if outputStream != nil || errorStream != nil {
go func() {
receiveStdout <- docker.redirectResponseToOutputStream(outputStream, errorStream, resp.Reader)
}()
}
stdinDone := make(chan struct{})
go func() {
if inputStream != nil {
io.Copy(resp.Conn, inputStream)
}
resp.CloseWrite()
close(stdinDone)
}()
select {
case err := <-receiveStdout:
return err
case <-stdinDone:
if outputStream != nil || errorStream != nil {
return <-receiveStdout
}
}
return nil
}
If you want to add CTRL+C to escape, you should set the DetachKeys
in ExecConfig
at ContainerExecCreate
. Otherwise executing exit
will detach it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论