master
go 76 lines 1.62 KB
Raw
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 }