An attempt at a new low level keybase interface that prevents each command from re-spawning a new keybase instance on low memory systems.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
1.6 KiB

package keybase
import (
"context"
"fmt"
"io"
"os/exec"
)
// apiCmd holds the pipes that connect to an executed command
type apiCmd struct {
Stderr io.ReadCloser
Stdin io.WriteCloser
Stdout io.ReadCloser
startFunc func() error
}
type cmd interface {
Start() error
Stdin() io.WriteCloser
Stdout() io.ReadCloser
Stderr() io.ReadCloser
}
type defaultCmd struct {
apiCmd *apiCmd
}
func (c *defaultCmd) Start() error {
return c.apiCmd.startFunc()
}
func (c *defaultCmd) Stdin() io.WriteCloser {
return c.apiCmd.Stdin
}
func (c *defaultCmd) Stdout() io.ReadCloser {
return c.apiCmd.Stdout
}
func (c *defaultCmd) Stderr() io.ReadCloser {
return c.apiCmd.Stderr
}
var _ cmd = &defaultCmd{}
func newApiCmd(ctx context.Context, execCmd string, args ...string) (cmd, error) {
var err error
// create a new apiCmd
cmd := &apiCmd{}
// set up the command
api := exec.CommandContext(ctx, execCmd, args...)
// an empty start func for failures
cmd.startFunc = func() error { return nil }
// hook up the stderr pipe
if cmd.Stderr, err = api.StderrPipe(); err != nil {
return nil, fmt.Errorf("failed to get pipe: %v", err)
}
// hook up the stdout pipe
if cmd.Stdout, err = api.StdoutPipe(); err != nil {
return nil, fmt.Errorf("failed to get pipe: %v", err)
}
// hook up the stdin pipe
if cmd.Stdin, err = api.StdinPipe(); err != nil {
return nil, fmt.Errorf("failed to get pipe: %v", err)
}
// create an anonymous function to start the commands
cmd.startFunc = func() error {
if err := api.Start(); err != nil {
return fmt.Errorf("failed to start command: %v", err)
}
return nil
}
return &defaultCmd{cmd}, nil
}