From 3e062f6e1ed31ae45ca619ac4a2813a9f6a86440 Mon Sep 17 00:00:00 2001 From: Matt Bell <mappum@gmail.com> Date: Thu, 23 Oct 2014 16:35:40 -0700 Subject: [PATCH] cmd/ipfs: Rewrote entry point to invoke commands via new command API --- cmd/ipfs/ipfs.go | 220 ++++++++--------------------------------------- 1 file changed, 34 insertions(+), 186 deletions(-) diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go index 9ce5d7faf..a37a44e7b 100644 --- a/cmd/ipfs/ipfs.go +++ b/cmd/ipfs/ipfs.go @@ -1,220 +1,68 @@ package main import ( - "errors" "fmt" + "io" "os" "runtime/pprof" - flag "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag" - commander "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander" - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - - config "github.com/jbenet/go-ipfs/config" - core "github.com/jbenet/go-ipfs/core" - daemon "github.com/jbenet/go-ipfs/daemon" - updates "github.com/jbenet/go-ipfs/updates" + cmds "github.com/jbenet/go-ipfs/commands" + "github.com/jbenet/go-ipfs/commands/cli" + "github.com/jbenet/go-ipfs/core/commands" u "github.com/jbenet/go-ipfs/util" ) -// The IPFS command tree. It is an instance of `commander.Command`. -var CmdIpfs = &commander.Command{ - UsageLine: "ipfs [<flags>] <command> [<args>]", - Short: "global versioned p2p merkledag file system", - Long: `ipfs - global versioned p2p merkledag file system - -Basic commands: - - init Initialize ipfs local configuration. - add <path> Add an object to ipfs. - cat <ref> Show ipfs object data. - ls <ref> List links from an object. - refs <ref> List link hashes from an object. - -Tool commands: - - config Manage configuration. - update Download and apply go-ipfs updates. - version Show ipfs version information. - commands List all available commands. - -Advanced Commands: - - mount Mount an ipfs read-only mountpoint. - serve Serve an interface to ipfs. - net-diag Print network diagnostic - -Plumbing commands: - - block Interact with raw blocks in the datastore - object Interact with raw dag nodes - - -Use "ipfs help <command>" for more information about a command. -`, - Run: ipfsCmd, - Subcommands: []*commander.Command{ - cmdIpfsAdd, - cmdIpfsCat, - cmdIpfsLs, - cmdIpfsRefs, - cmdIpfsConfig, - cmdIpfsVersion, - cmdIpfsCommands, - cmdIpfsMount, - cmdIpfsInit, - cmdIpfsServe, - cmdIpfsRun, - cmdIpfsName, - cmdIpfsBootstrap, - cmdIpfsDiag, - cmdIpfsBlock, - cmdIpfsObject, - cmdIpfsUpdate, - cmdIpfsLog, - cmdIpfsPin, - cmdIpfsTour, - }, - Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError), -} - // log is the command logger var log = u.Logger("cmd/ipfs") -func init() { - config, err := config.PathRoot() - if err != nil { - fmt.Fprintln(os.Stderr, "Failure initializing the default Config Directory: ", err) - os.Exit(1) - } - CmdIpfs.Flag.String("c", config, "specify config directory") -} - -func ipfsCmd(c *commander.Command, args []string) error { - u.POut(c.Long) - return nil -} +const API_PATH = "/api/v0" func main() { - // if debugging, setup profiling. - if u.Debug { - ofi, err := os.Create("cpu.prof") - if err != nil { - fmt.Println(err) - return - } - pprof.StartCPUProfile(ofi) - defer ofi.Close() - defer pprof.StopCPUProfile() - } - - err := CmdIpfs.Dispatch(os.Args[1:]) + req, err := cli.Parse(os.Args[1:], commands.Root) if err != nil { - if len(err.Error()) > 0 { - fmt.Fprintf(os.Stderr, "ipfs %s: %v\n", os.Args[1], err) - } + fmt.Println(err) os.Exit(1) } - return -} -// localNode constructs a node -func localNode(confdir string, online bool) (*core.IpfsNode, error) { - filename, err := config.Filename(confdir) + cmd, err := commands.Root.Get(req.Path()) if err != nil { - return nil, err - } - - cfg, err := config.Load(filename) - if err != nil { - return nil, err - } - - if err := updates.CliCheckForUpdates(cfg, filename); err != nil { - return nil, err - } - - return core.NewIpfsNode(cfg, online) -} - -// Gets the config "-c" flag from the command, or returns -// the default configuration root directory -func getConfigDir(c *commander.Command) (string, error) { - - // use the root cmd (that's where config is specified) - for ; c.Parent != nil; c = c.Parent { - } - - // flag should be defined on root. - param := c.Flag.Lookup("c").Value.Get().(string) - if param != "" { - return u.TildeExpansion(param) - } - - return config.PathRoot() -} - -func getConfig(c *commander.Command) (*config.Config, error) { - confdir, err := getConfigDir(c) - if err != nil { - return nil, err - } - - filename, err := config.Filename(confdir) - if err != nil { - return nil, err + fmt.Println(err) + os.Exit(1) } - return config.Load(filename) -} - -// cmdContext is a wrapper structure that keeps a node, a daemonlistener, and -// a config directory together. These three are needed for most commands. -type cmdContext struct { - node *core.IpfsNode - daemon *daemon.DaemonListener - configDir string -} + // TODO: send request to daemon via HTTP API -// setupCmdContext initializes a cmdContext structure from a given command. -func setupCmdContext(c *commander.Command, online bool) (cc cmdContext, err error) { - rootCmd := c - for ; rootCmd.Parent != nil; rootCmd = rootCmd.Parent { - } + if debug, ok := req.Option("debug"); ok && debug.(bool) { + u.Debug = true - cc.configDir, err = getConfigDir(rootCmd) - if err != nil { - return + // if debugging, setup profiling. + if u.Debug { + ofi, err := os.Create("cpu.prof") + if err != nil { + fmt.Println(err) + return + } + pprof.StartCPUProfile(ofi) + defer ofi.Close() + defer pprof.StopCPUProfile() + } } - cc.node, err = localNode(cc.configDir, online) - if err != nil { - return - } + res := commands.Root.Call(req) - cc.daemon, err = setupDaemon(cc.configDir, cc.node) - if err != nil { - return - } - - return -} + if res.Error() != nil { + fmt.Println(res.Error().Error()) -// setupDaemon sets up the daemon corresponding to given node. -func setupDaemon(confdir string, node *core.IpfsNode) (*daemon.DaemonListener, error) { - if node.Config.Addresses.API == "" { - return nil, errors.New("no config.Addresses.API endpoint supplied") - } + if cmd.Help != "" && res.Error().Code == cmds.ErrClient { + // TODO: convert from markdown to ANSI terminal format? + fmt.Println(cmd.Help) + } - maddr, err := ma.NewMultiaddr(node.Config.Addresses.API) - if err != nil { - return nil, err + os.Exit(1) } - dl, err := daemon.NewDaemonListener(node, maddr, confdir) + _, err = io.Copy(os.Stdout, res) if err != nil { - return nil, err + fmt.Println(err.Error()) } - go dl.Listen() - return dl, nil } -- GitLab