blob: f44127b726172b5bfb7249dadf042d49979f4a28 [file] [log] [blame]
package modules
import (
"bufio"
"fmt"
"io"
"os"
"sync"
)
type pipe struct {
r, w *os.File
}
type functionHandle struct {
mu sync.Mutex
main Main
stdin, stderr, stdout pipe
err error
sh *Shell
wg sync.WaitGroup
}
func newFunctionHandle(main Main) command {
return &functionHandle{main: main}
}
func (fh *functionHandle) Stdout() io.Reader {
fh.mu.Lock()
defer fh.mu.Unlock()
return fh.stdout.r
}
func (fh *functionHandle) Stderr() io.Reader {
fh.mu.Lock()
defer fh.mu.Unlock()
return fh.stderr.r
}
func (fh *functionHandle) Stdin() io.Writer {
fh.mu.Lock()
defer fh.mu.Unlock()
return fh.stdin.w
}
func (fh *functionHandle) CloseStdin() {
fh.mu.Lock()
fh.stdin.w.Close()
fh.mu.Unlock()
}
func (fh *functionHandle) start(sh *Shell, args ...string) (Handle, error) {
fh.mu.Lock()
defer fh.mu.Unlock()
fh.sh = sh
for _, p := range []*pipe{&fh.stdin, &fh.stdout, &fh.stderr} {
var err error
if p.r, p.w, err = os.Pipe(); err != nil {
return nil, err
}
}
fh.wg.Add(1)
go func() {
fh.mu.Lock()
stdin := fh.stdin.r
stdout := fh.stdout.w
stderr := fh.stderr.w
main := fh.main
fh.mu.Unlock()
err := main(stdin, stdout, stderr, sh.mergeOSEnv(), args...)
if err != nil {
fmt.Fprintf(stderr, "%s\n", err)
}
fh.mu.Lock()
fh.stdin.r.Close()
fh.stdout.w.Close()
fh.stderr.w.Close()
fh.err = err
fh.mu.Unlock()
fh.wg.Done()
}()
return fh, nil
}
func (fh *functionHandle) Shutdown(output io.Writer) error {
fh.mu.Lock()
fh.stdin.w.Close()
stderr := fh.stderr.r
fh.mu.Unlock()
if output != nil {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
l := scanner.Text()
fmt.Fprintf(output, "%s\n", l)
}
}
fh.wg.Wait()
fh.mu.Lock()
fh.stdout.r.Close()
fh.stderr.r.Close()
err := fh.err
fh.sh.forget(fh)
fh.mu.Unlock()
return err
}