mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 10:27:46 +08:00
initial support for commands to use external binaries
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
parent
3a2ac8f037
commit
7681b66fee
@ -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)
|
||||
}
|
||||
|
||||
@ -9,9 +9,12 @@ output to the user, including text, JSON, and XML marshallers.
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@ -59,6 +62,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.
|
||||
@ -262,3 +269,67 @@ func checkArgValue(v string, found bool, def Argument) error {
|
||||
func ClientError(msg string) error {
|
||||
return &Error{Code: ErrClient, Message: msg}
|
||||
}
|
||||
|
||||
func ExternalBinary() *Command {
|
||||
return &Command{
|
||||
Arguments: []Argument{
|
||||
StringArg("args", false, true, "arguments for subcommand"),
|
||||
},
|
||||
External: true,
|
||||
Run: func(req Request, res Response) {
|
||||
binname := strings.Join(append([]string{"ipfs"}, req.Path()...), "-")
|
||||
_, err := exec.LookPath(binname)
|
||||
if err != nil {
|
||||
// special case for '--help' on uninstalled binaries.
|
||||
if req.Arguments()[0] == "--help" {
|
||||
buf := new(bytes.Buffer)
|
||||
fmt.Fprintf(buf, "%s is an 'external' command.\n", binname)
|
||||
fmt.Fprintf(buf, "it does not currently appear to be installated.\n")
|
||||
fmt.Fprintf(buf, "please refer to the ipfs documentation for instructions\n")
|
||||
res.SetOutput(buf)
|
||||
return
|
||||
}
|
||||
|
||||
res.SetError(fmt.Errorf("%s not installed."), 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), ErrNormal)
|
||||
return
|
||||
}
|
||||
|
||||
res.SetOutput(r)
|
||||
|
||||
go func() {
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
res.SetError(err, ErrNormal)
|
||||
}
|
||||
|
||||
w.Close()
|
||||
}()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ var rootSubcommands = map[string]*cmds.Command{
|
||||
"tar": TarCmd,
|
||||
"tour": tourCmd,
|
||||
"file": unixfs.UnixFSCmd,
|
||||
"update": UpdateCmd,
|
||||
"update": cmds.ExternalBinary(),
|
||||
"version": VersionCmd,
|
||||
"bitswap": BitswapCmd,
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user