containerd/io.go
Kenfe-Mickael Laventure a4aaa09ccc
Update ctr so it works again on windows
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
2017-07-21 18:19:48 +02:00

147 lines
2.5 KiB
Go

package containerd
import (
"context"
"fmt"
"io"
"os"
"sync"
)
type IO struct {
Terminal bool
Stdin string
Stdout string
Stderr string
closer *wgCloser
}
func (i *IO) Cancel() {
if i.closer == nil {
return
}
i.closer.Cancel()
}
func (i *IO) Wait() {
if i.closer == nil {
return
}
i.closer.Wait()
}
func (i *IO) Close() error {
if i.closer == nil {
return nil
}
return i.closer.Close()
}
type IOCreation func(id string) (*IO, error)
type IOAttach func(*FIFOSet) (*IO, error)
func NewIO(stdin io.Reader, stdout, stderr io.Writer) IOCreation {
return NewIOWithTerminal(stdin, stdout, stderr, false)
}
func NewIOWithTerminal(stdin io.Reader, stdout, stderr io.Writer, terminal bool) IOCreation {
return func(id string) (*IO, error) {
paths, err := NewFifos(id)
if err != nil {
return nil, err
}
i := &IO{
Terminal: terminal,
Stdout: paths.Out,
Stderr: paths.Err,
Stdin: paths.In,
}
set := &ioSet{
in: stdin,
out: stdout,
err: stderr,
}
closer, err := copyIO(paths, set, i.Terminal)
if err != nil {
return nil, err
}
i.closer = closer
return i, nil
}
}
func WithAttach(stdin io.Reader, stdout, stderr io.Writer) IOAttach {
return func(paths *FIFOSet) (*IO, error) {
if paths == nil {
return nil, fmt.Errorf("cannot attach to existing fifos")
}
i := &IO{
Terminal: paths.Terminal,
Stdout: paths.Out,
Stderr: paths.Err,
Stdin: paths.In,
}
set := &ioSet{
in: stdin,
out: stdout,
err: stderr,
}
closer, err := copyIO(paths, set, i.Terminal)
if err != nil {
return nil, err
}
i.closer = closer
return i, nil
}
}
// Stdio returns an IO implementation to be used for a task
// that outputs the container's IO as the current processes Stdio
func Stdio(id string) (*IO, error) {
return NewIO(os.Stdin, os.Stdout, os.Stderr)(id)
}
// StdioTerminal will setup the IO for the task to use a terminal
func StdioTerminal(id string) (*IO, error) {
return NewIOWithTerminal(os.Stdin, os.Stdout, os.Stderr, true)(id)
}
type FIFOSet struct {
// Dir is the directory holding the task fifos
Dir string
In, Out, Err string
Terminal bool
}
type ioSet struct {
in io.Reader
out, err io.Writer
}
type wgCloser struct {
wg *sync.WaitGroup
dir string
set []io.Closer
cancel context.CancelFunc
}
func (g *wgCloser) Wait() {
g.wg.Wait()
}
func (g *wgCloser) Close() error {
for _, f := range g.set {
f.Close()
}
if g.dir != "" {
return os.RemoveAll(g.dir)
}
return nil
}
func (g *wgCloser) Cancel() {
g.cancel()
}