diff --git a/README.md b/README.md index fa1a3eb0d3c..532871c0634 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ dependencies as well. * Shell command completion is available in `misc/completion/ipfs-completion.bash`. Read [docs/command-completion.md](docs/command-completion.md) to learn how to install it. * See the [init examples](https://github.com/ipfs/examples/tree/master/examples/init) for how to connect IPFS to systemd or whatever init system your distro uses. +### Updating +ipfs has an updating tool that can be accessed through `ipfs update`. The tool is +not installed alongside ipfs in order to keep that logic independent of the main +codebase. To install ipfs update, either [download it here](https://gobuilder.me/github.com/ipfs/ipfs-update) +or install it from source with `go get -u github.com/ipfs/ipfs-update`. ## Usage diff --git a/commands/cli/parse.go b/commands/cli/parse.go index f758429b8ba..ea12881ec53 100644 --- a/commands/cli/parse.go +++ b/commands/cli/parse.go @@ -204,6 +204,13 @@ func parseOpts(args []string, root *cmds.Command) ( if err != nil { return } + + // If we've come across an external binary call, pass all the remaining + // arguments on to it + if cmd.External { + stringVals = append(stringVals, args[i+1:]...) + return + } } else { stringVals = append(stringVals, arg) } diff --git a/commands/command.go b/commands/command.go index 53897674872..84cb05c737d 100644 --- a/commands/command.go +++ b/commands/command.go @@ -59,6 +59,10 @@ type Command struct { Marshalers map[EncodingType]Marshaler Helptext HelpText + // External denotes that a command is actually an external binary. + // fewer checks and validations will be performed on such commands. + External bool + // Type describes the type of the output of the Command's Run Function. // In precise terms, the value of Type is an instance of the return type of // the Run Function. diff --git a/core/commands/external.go b/core/commands/external.go new file mode 100644 index 00000000000..c7edc474402 --- /dev/null +++ b/core/commands/external.go @@ -0,0 +1,78 @@ +package commands + +import ( + "bytes" + "fmt" + "io" + "os" + "os/exec" + "strings" + + cmds "github.com/ipfs/go-ipfs/commands" +) + +func ExternalBinary() *cmds.Command { + return &cmds.Command{ + Arguments: []cmds.Argument{ + cmds.StringArg("args", false, true, "arguments for subcommand"), + }, + 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) + fmt.Fprintf(buf, "it does not currently appear to be installed.\n") + fmt.Fprintf(buf, "please refer to the ipfs documentation for instructions\n") + res.SetOutput(buf) + return + } + } + + res.SetError(fmt.Errorf("%s not installed."), cmds.ErrNormal) + 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() + + nd, err := req.InvocContext().GetNode() + if err == nil { + env = append(env, fmt.Sprintf("IPFS_ONLINE=%t", nd.OnlineMode())) + } + + cmd.Env = env + + err = cmd.Start() + if err != nil { + res.SetError(fmt.Errorf("failed to start subcommand: %s", err), cmds.ErrNormal) + return + } + + res.SetOutput(r) + + go func() { + err = cmd.Wait() + if err != nil { + res.SetError(err, cmds.ErrNormal) + } + + w.Close() + }() + }, + } +} diff --git a/core/commands/root.go b/core/commands/root.go index ce67217502e..2edcfd3c006 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -111,7 +111,7 @@ var rootSubcommands = map[string]*cmds.Command{ "tar": TarCmd, "tour": tourCmd, "file": unixfs.UnixFSCmd, - "update": UpdateCmd, + "update": ExternalBinary(), "version": VersionCmd, "bitswap": BitswapCmd, }