| 1 | package commands |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "fmt" |
| 6 | "io" |
| 7 | "os" |
| 8 | "os/exec" |
| 9 | "strings" |
| 10 | |
| 11 | cmds "github.com/ipfs/go-ipfs-cmds" |
| 12 | ) |
| 13 | |
| 14 | func ExternalBinary(instructions string) *cmds.Command { |
| 15 | return &cmds.Command{ |
| 16 | Arguments: []cmds.Argument{ |
| 17 | cmds.StringArg("args", false, true, "Arguments for subcommand."), |
| 18 | }, |
| 19 | External: true, |
| 20 | NoRemote: true, |
| 21 | Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { |
| 22 | binname := strings.Join(append([]string{"ipfs"}, req.Path...), "-") |
| 23 | _, err := exec.LookPath(binname) |
| 24 | if err != nil { |
| 25 | // special case for '--help' on uninstalled binaries. |
| 26 | for _, arg := range req.Arguments { |
| 27 | if arg == "--help" || arg == "-h" { |
| 28 | buf := new(bytes.Buffer) |
| 29 | fmt.Fprintf(buf, "%s is an 'external' command.\n", binname) |
| 30 | fmt.Fprintf(buf, "It does not currently appear to be installed.\n") |
| 31 | fmt.Fprintf(buf, "%s\n", instructions) |
| 32 | return res.Emit(buf) |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | return fmt.Errorf("%s not installed", binname) |
| 37 | } |
| 38 | |
| 39 | r, w := io.Pipe() |
| 40 | |
| 41 | cmd := exec.Command(binname, req.Arguments...) |
| 42 | |
| 43 | // TODO: make commands lib be able to pass stdin through daemon |
| 44 | // cmd.Stdin = req.Stdin() |
| 45 | cmd.Stdin = io.LimitReader(nil, 0) |
| 46 | cmd.Stdout = w |
| 47 | cmd.Stderr = w |
| 48 | |
| 49 | // setup env of child program |
| 50 | osenv := os.Environ() |
| 51 | |
| 52 | cmd.Env = osenv |
| 53 | |
| 54 | err = cmd.Start() |
| 55 | if err != nil { |
| 56 | return fmt.Errorf("failed to start subcommand: %s", err) |
| 57 | } |
| 58 | |
| 59 | errC := make(chan error) |
| 60 | |
| 61 | go func() { |
| 62 | var err error |
| 63 | defer func() { errC <- err }() |
| 64 | err = cmd.Wait() |
| 65 | w.Close() |
| 66 | }() |
| 67 | |
| 68 | err = res.Emit(r) |
| 69 | if err != nil { |
| 70 | return err |
| 71 | } |
| 72 | |
| 73 | return <-errC |
| 74 | }, |
| 75 | } |
| 76 | } |