external.go 2.01 KB
Newer Older
Jeromy's avatar
Jeromy committed
1 2 3 4 5 6 7 8 9 10 11
package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
Jan Winkelmann's avatar
Jan Winkelmann committed
12

13
	"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
Jeromy's avatar
Jeromy committed
14 15 16 17
)

func ExternalBinary() *cmds.Command {
	return &cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
18 19
		Arguments: []cmdkit.Argument{
			cmdkit.StringArg("args", false, true, "Arguments for subcommand."),
Jeromy's avatar
Jeromy committed
20 21 22 23 24 25 26 27 28 29 30
		},
		External: true,
		Run: func(req cmds.Request, res cmds.Response) {
			binname := strings.Join(append([]string{"ipfs"}, req.Path()...), "-")
			_, err := exec.LookPath(binname)
			if err != nil {
				// special case for '--help' on uninstalled binaries.
				for _, arg := range req.Arguments() {
					if arg == "--help" || arg == "-h" {
						buf := new(bytes.Buffer)
						fmt.Fprintf(buf, "%s is an 'external' command.\n", binname)
31 32
						fmt.Fprintf(buf, "It does not currently appear to be installed.\n")
						fmt.Fprintf(buf, "Please refer to the ipfs documentation for instructions.\n")
Jeromy's avatar
Jeromy committed
33 34 35 36 37
						res.SetOutput(buf)
						return
					}
				}

Jan Winkelmann's avatar
Jan Winkelmann committed
38
				res.SetError(fmt.Errorf("%s not installed", binname), cmdkit.ErrNormal)
Jeromy's avatar
Jeromy committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
				return
			}

			r, w := io.Pipe()

			cmd := exec.Command(binname, req.Arguments()...)

			// TODO: make commands lib be able to pass stdin through daemon
			//cmd.Stdin = req.Stdin()
			cmd.Stdin = io.LimitReader(nil, 0)
			cmd.Stdout = w
			cmd.Stderr = w

			// setup env of child program
			env := os.Environ()

55 56 57 58 59 60 61 62 63 64
			// Get the node iff already defined.
			if req.InvocContext().Online {
				nd, err := req.InvocContext().GetNode()
				if err != nil {
					res.SetError(fmt.Errorf(
						"failed to start ipfs node: %s",
						err,
					), cmdkit.ErrFatal)
					return
				}
Jeromy's avatar
Jeromy committed
65 66 67 68 69 70 71
				env = append(env, fmt.Sprintf("IPFS_ONLINE=%t", nd.OnlineMode()))
			}

			cmd.Env = env

			err = cmd.Start()
			if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
72
				res.SetError(fmt.Errorf("failed to start subcommand: %s", err), cmdkit.ErrNormal)
Jeromy's avatar
Jeromy committed
73 74 75 76 77 78 79 80
				return
			}

			res.SetOutput(r)

			go func() {
				err = cmd.Wait()
				if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
81
					res.SetError(err, cmdkit.ErrNormal)
Jeromy's avatar
Jeromy committed
82 83 84 85 86 87 88
				}

				w.Close()
			}()
		},
	}
}