From f28752494989792342168e0d7422bfb81ae508f1 Mon Sep 17 00:00:00 2001 From: Jan Winkelmann Date: Sat, 1 Apr 2017 16:58:17 +0200 Subject: [PATCH 1/3] cmd: use go-ipfs-cmds License: MIT Signed-off-by: keks --- blocks/blockstore/caching.go | 1 + blocks/blockstore/util/remove.go | 15 +- cmd/ipfs/daemon.go | 80 ++--- cmd/ipfs/init.go | 37 ++- cmd/ipfs/ipfs.go | 34 ++- cmd/ipfs/main.go | 153 ++++++---- cmd/ipfs/main_test.go | 11 +- cmd/ipfswatch/main.go | 3 +- cmd/seccat/seccat.go | 2 +- commands/argument.go | 56 ---- commands/channelmarshaler.go | 4 +- commands/cli/cmd_suggestion.go | 8 +- commands/cli/helptext.go | 13 +- commands/cli/helptext_test.go | 14 +- commands/cli/parse.go | 30 +- commands/cli/parse_test.go | 58 ++-- commands/command.go | 58 ++-- commands/command_test.go | 30 +- commands/files/file.go | 62 ---- commands/files/file_test.go | 203 ------------- commands/files/is_hidden.go | 19 -- commands/files/is_hidden_windows.go | 29 -- commands/files/linkfile.go | 50 ---- commands/files/multipartfile.go | 115 ------- commands/files/readerfile.go | 70 ----- commands/files/serialfile.go | 154 ---------- commands/files/slicefile.go | 76 ----- commands/http/client.go | 27 +- commands/http/handler.go | 9 +- commands/http/multifilereader.go | 2 +- commands/http/multifilereader_test.go | 2 +- commands/http/parse.go | 15 +- commands/option.go | 209 ------------- commands/option_test.go | 45 --- commands/reqlog.go | 56 ++-- commands/request.go | 46 +-- commands/response.go | 35 +-- commands/response_test.go | 10 +- core/bootstrap.go | 2 +- core/commands/active.go | 31 +- core/commands/add.go | 314 +++++++++++--------- core/commands/bitswap.go | 156 +++++----- core/commands/block.go | 160 +++++----- core/commands/bootstrap.go | 131 ++++---- core/commands/cat.go | 76 +++-- core/commands/commands.go | 117 ++++++-- core/commands/config.go | 84 +++--- core/commands/dag/dag.go | 103 ++++--- core/commands/dht.go | 274 ++++++++--------- core/commands/diag.go | 8 +- core/commands/dns.go | 27 +- core/commands/e/error.go | 30 ++ core/commands/external.go | 12 +- core/commands/files/files.go | 298 +++++++++++-------- core/commands/filestore.go | 181 ++++++----- core/commands/get.go | 115 ++++--- core/commands/helptext_test.go | 2 +- core/commands/id.go | 41 +-- core/commands/ipns.go | 35 ++- core/commands/keystore.go | 120 ++++---- core/commands/log.go | 21 +- core/commands/ls.go | 44 ++- core/commands/mount_nofuse.go | 4 +- core/commands/mount_unix.go | 38 ++- core/commands/mount_windows.go | 6 +- core/commands/name.go | 8 +- core/commands/object/diff.go | 37 ++- core/commands/object/object.go | 173 +++++++---- core/commands/object/patch.go | 115 +++---- core/commands/p2p.go | 105 ++++--- core/commands/pin.go | 198 ++++++------ core/commands/ping.go | 66 ++-- core/commands/publish.go | 49 +-- core/commands/pubsub.go | 190 ++++++------ core/commands/refs.go | 78 ++--- core/commands/repo.go | 279 ++++++++--------- core/commands/resolve.go | 33 +- core/commands/root.go | 85 ++++-- core/commands/shutdown.go | 10 +- core/commands/stat.go | 154 +++++----- core/commands/swarm.go | 167 ++++++----- core/commands/sysdiag.go | 15 +- core/commands/tar.go | 43 ++- core/commands/unixfs/ls.go | 35 ++- core/commands/unixfs/unixfs.go | 23 +- core/commands/version.go | 34 ++- core/core_test.go | 1 + core/corehttp/commands.go | 11 +- core/corehttp/gateway.go | 1 + core/coreunix/add.go | 2 +- core/coreunix/add_test.go | 2 +- core/coreunix/metadata_test.go | 2 +- exchange/bitswap/bitswap_test.go | 6 +- exchange/bitswap/decision/engine_test.go | 2 +- exchange/bitswap/message/message_test.go | 4 +- exchange/bitswap/message/pb/Makefile | 8 + exchange/bitswap/testnet/network_test.go | 2 +- exchange/bitswap/testnet/peernet.go | 1 + exchange/reprovide/reprovide_test.go | 2 +- fuse/ipns/common.go | 2 +- fuse/node/mount_test.go | 3 +- importer/balanced/balanced_test.go | 2 +- importer/chunk/rabin_test.go | 5 +- importer/helpers/dagbuilder.go | 2 +- importer/importer.go | 2 +- merkledag/utils/utils_test.go | 2 +- mfs/repub_test.go | 5 +- namesys/dns.go | 1 - namesys/interface.go | 1 + namesys/ipns_select_test.go | 4 +- namesys/proquint.go | 1 + namesys/republisher/repub_test.go | 6 +- package.json | 10 + repo/config/identity.go | 1 + routing/offline/offline_test.go | 5 +- test/integration/addcat_test.go | 3 +- test/integration/bench_cat_test.go | 3 +- test/integration/bitswap_wo_routing_test.go | 2 +- test/integration/three_legged_cat_test.go | 4 +- 119 files changed, 2928 insertions(+), 3348 deletions(-) delete mode 100644 commands/argument.go delete mode 100644 commands/files/file.go delete mode 100644 commands/files/file_test.go delete mode 100644 commands/files/is_hidden.go delete mode 100644 commands/files/is_hidden_windows.go delete mode 100644 commands/files/linkfile.go delete mode 100644 commands/files/multipartfile.go delete mode 100644 commands/files/readerfile.go delete mode 100644 commands/files/serialfile.go delete mode 100644 commands/files/slicefile.go delete mode 100644 commands/option.go delete mode 100644 commands/option_test.go create mode 100644 core/commands/e/error.go create mode 100644 exchange/bitswap/message/pb/Makefile diff --git a/blocks/blockstore/caching.go b/blocks/blockstore/caching.go index 0ea375b06..5d6f3bc85 100644 --- a/blocks/blockstore/caching.go +++ b/blocks/blockstore/caching.go @@ -4,6 +4,7 @@ import ( "errors" context "context" + "gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface" ) diff --git a/blocks/blockstore/util/remove.go b/blocks/blockstore/util/remove.go index 47552988b..467f55092 100644 --- a/blocks/blockstore/util/remove.go +++ b/blocks/blockstore/util/remove.go @@ -85,12 +85,17 @@ func FilterPinned(pins pin.Pinner, out chan<- interface{}, cids []*cid.Cid) []*c return stillOkay } -// ProcRmOutput takes the channel returned by RmBlocks and writes -// to stdout/stderr according to the RemovedBlock objects received in -// that channel. -func ProcRmOutput(in <-chan interface{}, sout io.Writer, serr io.Writer) error { +// ProcRmOutput takes a function which returns a result from RmBlocks or EOF if there is no input. +// It then writes to stdout/stderr according to the RemovedBlock object returned from the function. +func ProcRmOutput(next func() (interface{}, error), sout io.Writer, serr io.Writer) error { someFailed := false - for res := range in { + for { + res, err := next() + if err == io.EOF { + break + } else if err != nil { + return err + } r := res.(*RemovedBlock) if r.Hash == "" && r.Error != "" { return fmt.Errorf("aborted: %s", r.Error) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 54313691e..ec5fb775a 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -11,7 +11,6 @@ import ( "sort" "sync" - cmds "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" commands "github.com/ipfs/go-ipfs/core/commands" corehttp "github.com/ipfs/go-ipfs/core/corehttp" @@ -20,6 +19,8 @@ import ( fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" migrate "github.com/ipfs/go-ipfs/repo/fsrepo/migrations" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" mprome "gx/ipfs/QmSk46nSD78YiuNojYMS8NW6hSCjH95JajqqzzoychZgef/go-metrics-prometheus" "gx/ipfs/QmX3QZ5jHEPidwUrymXV1iSCSUhdGxj15sm2gP4jKMef7B/client_golang/prometheus" "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net" @@ -51,7 +52,7 @@ const ( ) var daemonCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Run a network-connected IPFS node.", ShortDescription: ` 'ipfs daemon' runs a persistent ipfs daemon that can serve commands @@ -142,24 +143,25 @@ Headers. `, }, - Options: []cmds.Option{ - cmds.BoolOption(initOptionKwd, "Initialize ipfs with default settings if not already initialized").Default(false), - cmds.StringOption(routingOptionKwd, "Overrides the routing option").Default("dht"), - cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem").Default(false), - cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)").Default(false), - cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."), - cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."), - cmds.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes").Default(false), - cmds.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)").Default(false), - cmds.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection").Default(false), - cmds.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").Default(true), - cmds.BoolOption(offlineKwd, "Run offline. Do not connect to the rest of the network but provide local API.").Default(false), - cmds.BoolOption(migrateKwd, "If true, assume yes at the migrate prompt. If false, assume no."), - cmds.BoolOption(enableFloodSubKwd, "Instantiate the ipfs daemon with the experimental pubsub feature enabled."), - cmds.BoolOption(enableMultiplexKwd, "Add the experimental 'go-multiplex' stream muxer to libp2p on construction.").Default(true), + Options: []cmdkit.Option{ + cmdkit.BoolOption(initOptionKwd, "Initialize ipfs with default settings if not already initialized").Default(false), + cmdkit.StringOption(routingOptionKwd, "Overrides the routing option").Default("dht"), + cmdkit.BoolOption(mountKwd, "Mounts IPFS to the filesystem").Default(false), + cmdkit.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)").Default(false), + cmdkit.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."), + cmdkit.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."), + cmdkit.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes").Default(false), + cmdkit.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)").Default(false), + cmdkit.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection").Default(false), + cmdkit.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").Default(true), + cmdkit.BoolOption(offlineKwd, "Run offline. Do not connect to the rest of the network but provide local API.").Default(false), + cmdkit.BoolOption(migrateKwd, "If true, assume yes at the migrate prompt. If false, assume no."), + cmdkit.BoolOption(enableFloodSubKwd, "Instantiate the ipfs daemon with the experimental pubsub feature enabled."), + cmdkit.BoolOption(enableMultiplexKwd, "Add the experimental 'go-multiplex' stream muxer to libp2p on construction.").Default(true), + // TODO: add way to override addresses. tricky part: updating the config if also --init. - // cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"), - // cmds.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"), + // cmdkit.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"), + // cmdkit.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"), }, Subcommands: map[string]*cmds.Command{}, Run: daemonFunc, @@ -178,7 +180,7 @@ func defaultMux(path string) corehttp.ServeOption { var fileDescriptorCheck = func() error { return nil } -func daemonFunc(req cmds.Request, res cmds.Response) { +func daemonFunc(req cmds.Request, re cmds.ResponseEmitter) { // Inject metrics before we do anything err := mprome.Inject() @@ -216,7 +218,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { // running in an uninitialized state. initialize, _, err := req.Option(initOptionKwd).Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } @@ -226,7 +228,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { if !fsrepo.IsInitialized(cfg) { err := initWithDefaults(os.Stdout, cfg) if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } } @@ -237,7 +239,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { repo, err := fsrepo.Open(ctx.ConfigRoot) switch err { default: - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return case fsrepo.ErrNeedMigration: domigrate, found, _ := req.Option(migrateKwd).Bool() @@ -250,7 +252,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { if !domigrate { fmt.Println("Not running migrations of fs-repo now.") fmt.Println("Please get fs-repo-migrations from https://dist.ipfs.io") - res.SetError(fmt.Errorf("fs-repo requires migration"), cmds.ErrNormal) + re.SetError(fmt.Errorf("fs-repo requires migration"), cmdkit.ErrNormal) return } @@ -260,13 +262,13 @@ func daemonFunc(req cmds.Request, res cmds.Response) { fmt.Printf(" %s\n", err) fmt.Println("If you think this is a bug, please file an issue and include this whole log output.") fmt.Println(" https://github.com/ipfs/fs-repo-migrations") - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } repo, err = fsrepo.Open(ctx.ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } case nil: @@ -275,7 +277,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { cfg, err := ctx.GetConfig() if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } @@ -297,12 +299,12 @@ func daemonFunc(req cmds.Request, res cmds.Response) { routingOption, _, err := req.Option(routingOptionKwd).String() if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } switch routingOption { case routingOptionSupernodeKwd: - res.SetError(errors.New("supernode routing was never fully implemented and has been removed"), cmds.ErrNormal) + re.SetError(errors.New("supernode routing was never fully implemented and has been removed"), cmdkit.ErrNormal) return case routingOptionDHTClientKwd: ncfg.Routing = core.DHTClientOption @@ -311,14 +313,14 @@ func daemonFunc(req cmds.Request, res cmds.Response) { case routingOptionNoneKwd: ncfg.Routing = core.NilRouterOption default: - res.SetError(fmt.Errorf("unrecognized routing option: %s", routingOption), cmds.ErrNormal) + re.SetError(fmt.Errorf("unrecognized routing option: %s", routingOption), cmdkit.ErrNormal) return } node, err := core.NewNode(req.Context(), ncfg) if err != nil { log.Error("error from node construction: ", err) - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } node.SetLocal(false) @@ -349,24 +351,24 @@ func daemonFunc(req cmds.Request, res cmds.Response) { // construct api endpoint - every time err, apiErrc := serveHTTPApi(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } // construct fuse mountpoints - if the user provided the --mount flag mount, _, err := req.Option(mountKwd).Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } if mount && offline { - res.SetError(errors.New("mount is not currently supported in offline mode"), - cmds.ErrClient) + re.SetError(errors.New("mount is not currently supported in offline mode"), + cmdkit.ErrClient) return } if mount { if err := mountFuse(req); err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } } @@ -374,7 +376,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { // repo blockstore GC - if --enable-gc flag is present err, gcErrc := maybeRunGC(req, node) if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } @@ -384,7 +386,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { var err error err, gwErrc = serveHTTPGateway(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } } @@ -398,7 +400,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { for err := range merge(apiErrc, gwErrc, gcErrc) { if err != nil { log.Error(err) - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) } } } diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index b7a4baf75..991fa636f 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "errors" "fmt" @@ -9,13 +10,14 @@ import ( "path" "strings" - context "context" assets "github.com/ipfs/go-ipfs/assets" cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" namesys "github.com/ipfs/go-ipfs/namesys" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) const ( @@ -23,7 +25,7 @@ const ( ) var initCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Initializes ipfs config file.", ShortDescription: ` Initializes ipfs configuration files and generates a new keypair. @@ -44,18 +46,18 @@ environment variable: export IPFS_PATH=/path/to/ipfsrepo `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("default-config", false, false, "Initialize with the given configuration.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("default-config", false, false, "Initialize with the given configuration.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").Default(nBitsForKeypairDefault), - cmds.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage.").Default(false), - cmds.StringOption("profile", "p", "Apply profile settings to config. Multiple profiles can be separated by ','"), + Options: []cmdkit.Option{ + cmdkit.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").Default(nBitsForKeypairDefault), + cmdkit.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage.").Default(false), + cmdkit.StringOption("profile", "p", "Apply profile settings to config. Multiple profiles can be separated by ','"), // TODO need to decide whether to expose the override as a file or a // directory. That is: should we allow the user to also specify the // name of the file? - // TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs."), + // TODO cmdkit.StringOption("event-logs", "l", "Location for machine-readable event logs."), }, PreRun: func(req cmds.Request) error { daemonLocked, err := fsrepo.LockedByOtherProcess(req.InvocContext().ConfigRoot) @@ -73,20 +75,23 @@ environment variable: return nil }, Run: func(req cmds.Request, res cmds.Response) { + // needs to be called at least once + res.SetOutput(nil) + if req.InvocContext().Online { - res.SetError(errors.New("init must be run offline only!"), cmds.ErrNormal) + res.SetError(errors.New("init must be run offline only!"), cmdkit.ErrNormal) return } empty, _, err := req.Option("e").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } nBitsForKeypair, _, err := req.Option("b").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -96,20 +101,20 @@ environment variable: if f != nil { confFile, err := f.NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } conf = &config.Config{} if err := json.NewDecoder(confFile).Decode(conf); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } profile, _, err := req.Option("profile").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -119,7 +124,7 @@ environment variable: } if err := doInit(os.Stdout, req.InvocContext().ConfigRoot, empty, nBitsForKeypair, profiles, conf); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } }, diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go index d90fce79c..db4768610 100644 --- a/cmd/ipfs/ipfs.go +++ b/cmd/ipfs/ipfs.go @@ -3,8 +3,10 @@ package main import ( "fmt" - cmds "github.com/ipfs/go-ipfs/commands" + oldcmds "github.com/ipfs/go-ipfs/commands" commands "github.com/ipfs/go-ipfs/core/commands" + + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" ) // This is the CLI root, used for executing commands accessible to CLI clients. @@ -22,7 +24,7 @@ var commandsClientCmd = commands.CommandsCmd(Root) // They can override subcommands in commands.Root by defining a subcommand with the same name. var localCommands = map[string]*cmds.Command{ "daemon": daemonCmd, - "init": initCmd, + "init": cmds.NewCommand(initCmd), "commands": commandsClientCmd, } var localMap = make(map[*cmds.Command]bool) @@ -31,8 +33,14 @@ func init() { // setting here instead of in literal to prevent initialization loop // (some commands make references to Root) Root.Subcommands = localCommands + Root.OldSubcommands = map[string]*oldcmds.Command{} // copy all subcommands from commands.Root into this root (if they aren't already present) + for k, v := range commands.Root.OldSubcommands { + if _, found := Root.OldSubcommands[k]; !found { + Root.OldSubcommands[k] = v + } + } for k, v := range commands.Root.Subcommands { if _, found := Root.Subcommands[k]; !found { Root.Subcommands[k] = v @@ -88,17 +96,13 @@ func (d *cmdDetails) usesRepo() bool { return !d.doesNotUseRepo } // not being able to run on all the same contexts. This map describes these // properties so that other code can make decisions about whether to invoke a // command or return an error to the user. -var cmdDetailsMap = map[*cmds.Command]cmdDetails{ - initCmd: {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true, doesNotUseRepo: true}, - - // daemonCmd allows user to initialize the config. Thus, it may be called - // without using the config as input - daemonCmd: {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true}, - commandsClientCmd: {doesNotUseRepo: true}, - commands.CommandsDaemonCmd: {doesNotUseRepo: true}, - commands.VersionCmd: {doesNotUseConfigAsInput: true, doesNotUseRepo: true}, // must be permitted to run before init - commands.LogCmd: {cannotRunOnClient: true}, - commands.ActiveReqsCmd: {cannotRunOnClient: true}, - commands.RepoFsckCmd: {cannotRunOnDaemon: true}, - commands.ConfigCmd.Subcommand("edit"): {cannotRunOnDaemon: true, doesNotUseRepo: true}, +var cmdDetailsMap = map[string]cmdDetails{ + "init": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true, doesNotUseRepo: true}, + "daemon": {doesNotUseConfigAsInput: true, cannotRunOnDaemon: true}, + "commands": {doesNotUseRepo: true}, + "version": {doesNotUseConfigAsInput: true, doesNotUseRepo: true}, // must be permitted to run before init + "log": {cannotRunOnClient: true}, + "diag/cmds": {cannotRunOnClient: true}, + "repo/fsck": {cannotRunOnDaemon: true}, + "config/edit": {cannotRunOnDaemon: true, doesNotUseRepo: true}, } diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index dcb2df407..acdb0ecb5 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -18,9 +18,6 @@ import ( "syscall" "time" - cmds "github.com/ipfs/go-ipfs/commands" - cmdsCli "github.com/ipfs/go-ipfs/commands/cli" - cmdsHttp "github.com/ipfs/go-ipfs/commands/http" core "github.com/ipfs/go-ipfs/core" coreCmds "github.com/ipfs/go-ipfs/core/commands" "github.com/ipfs/go-ipfs/plugin/loader" @@ -28,6 +25,10 @@ import ( config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/cli" + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/http" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" loggables "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables" @@ -54,6 +55,12 @@ type cmdInvocation struct { node *core.IpfsNode } +type exitErr int + +func (e exitErr) Error() string { + return fmt.Sprint("exit code", int(e)) +} + // main roadmap: // - parse the commandline to get a cmdInvocation // - if user requests help, print it and exit. @@ -68,8 +75,6 @@ func mainRet() int { rand.Seed(time.Now().UnixNano()) ctx := logging.ContextWithLoggable(context.Background(), loggables.Uuid("session")) var err error - var invoc cmdInvocation - defer invoc.close() // we'll call this local helper to output errors. // this is so we control how to print errors in one place. @@ -84,12 +89,15 @@ func mainRet() int { } defer stopFunc() // to be executed as late as possible + var invoc cmdInvocation + defer invoc.close() + // this is a local helper to print out help text. // there's some considerations that this makes easier. printHelp := func(long bool, w io.Writer) { - helpFunc := cmdsCli.ShortHelp + helpFunc := cli.ShortHelp if long { - helpFunc = cmdsCli.LongHelp + helpFunc = cli.LongHelp } helpFunc("ipfs", Root, invoc.path, w) @@ -154,8 +162,12 @@ func mainRet() int { intrh, ctx := invoc.SetupInterruptHandler(ctx) defer intrh.Close() - output, err := invoc.Run(ctx) + err = invoc.Run(ctx) if err != nil { + if code, ok := err.(exitErr); ok { + return int(code) + } + printErr(err) // if this error was a client error, print short help too. @@ -166,20 +178,15 @@ func mainRet() int { } // everything went better than expected :) - _, err = io.Copy(os.Stdout, output) - if err != nil { - printErr(err) - return 1 - } return 0 } -func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) { +func (i *cmdInvocation) Run(ctx context.Context) error { // check if user wants to debug. option OR env var. debug, _, err := i.req.Option("debug").Bool() if err != nil { - return nil, err + return err } if debug || os.Getenv("IPFS_LOGGING") == "debug" { u.Debug = true @@ -189,20 +196,12 @@ func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) { u.Debug = true } - res, err := callCommand(ctx, i.req, Root, i.cmd) - if err != nil { - return nil, err - } - - if err := res.Error(); err != nil { - return nil, err - } - - return res.Reader() + err = callCommand(ctx, i.req, Root, i.cmd) + return err } func (i *cmdInvocation) constructNodeFunc(ctx context.Context) func() (*core.IpfsNode, error) { - return func() (*core.IpfsNode, error) { + return func() (n *core.IpfsNode, err error) { if i.req == nil { return nil, errors.New("constructing node without a request") } @@ -219,7 +218,7 @@ func (i *cmdInvocation) constructNodeFunc(ctx context.Context) func() (*core.Ipf // ok everything is good. set it on the invocation (for ownership) // and return it. - n, err := core.NewNode(ctx, &core.BuildCfg{ + n, err = core.NewNode(ctx, &core.BuildCfg{ Online: cmdctx.Online, Repo: r, }) @@ -245,7 +244,7 @@ func (i *cmdInvocation) close() { func (i *cmdInvocation) Parse(ctx context.Context, args []string) error { var err error - i.req, i.cmd, i.path, err = cmdsCli.Parse(args, os.Stdin, Root) + i.req, i.cmd, i.path, err = cli.Parse(args, os.Stdin, Root) if err != nil { return err } @@ -267,7 +266,7 @@ func (i *cmdInvocation) Parse(ctx context.Context, args []string) error { // if no encoding was specified by user, default to plaintext encoding // (if command doesn't support plaintext, use JSON instead) if !i.req.Option("encoding").Found() { - if i.req.Command().Marshalers != nil && i.req.Command().Marshalers[cmds.Text] != nil { + if i.req.Command().Encoders != nil && i.req.Command().Encoders[cmds.Text] != nil { i.req.SetOption("encoding", cmds.Text) } else { i.req.SetOption("encoding", cmds.JSON) @@ -297,70 +296,106 @@ func callPreCommandHooks(ctx context.Context, details cmdDetails, req cmds.Reque return nil } -func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) (cmds.Response, error) { +func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd *cmds.Command) error { log.Info(config.EnvDir, " ", req.InvocContext().ConfigRoot) - var res cmds.Response err := req.SetRootContext(ctx) if err != nil { - return nil, err + return err } details, err := commandDetails(req.Path(), root) if err != nil { - return nil, err + return err } client, err := commandShouldRunOnDaemon(*details, req, root) if err != nil { - return nil, err + return err } err = callPreCommandHooks(ctx, *details, req, root) if err != nil { - return nil, err + return err + } + + encTypeStr, found, err := req.Option("encoding").String() + if !found || err != nil { + log.Error("error getting encoding - using JSON. reason: ", err) + encTypeStr = "json" + } + encType := cmds.EncodingType(encTypeStr) + + var ( + re cmds.ResponseEmitter + exitCh <-chan int + ) + + // first if condition checks the command's encoder map, second checks global encoder map (cmd vs. cmds) + if enc, ok := cmd.Encoders[encType]; ok { + re, exitCh = cli.NewResponseEmitter(os.Stdout, os.Stderr, enc, req) + } else if enc, ok := cmds.Encoders[encType]; ok { + re, exitCh = cli.NewResponseEmitter(os.Stdout, os.Stderr, enc, req) + } else { + return fmt.Errorf("could not find matching encoder for enctype %#v", encType) } if cmd.PreRun != nil { err = cmd.PreRun(req) if err != nil { - return nil, err + return err } } + if cmd.PostRun != nil && cmd.PostRun[cmds.CLI] != nil { + re = cmd.PostRun[cmds.CLI](req, re) + } + if client != nil && !cmd.External { log.Debug("executing command via API") - res, err = client.Send(req) + + res, err := client.Send(req) if err != nil { if isConnRefused(err) { err = repo.ErrApiNotRunning } - return nil, wrapContextCanceled(err) + + return wrapContextCanceled(err) } + go func() { + err = cmds.Copy(re, res) + if err != nil { + re.SetError(err, cmdkit.ErrNormal|cmdkit.ErrFatal) + } + }() } else { log.Debug("executing command locally") pluginpath := filepath.Join(req.InvocContext().ConfigRoot, "plugins") if _, err := loader.LoadPlugins(pluginpath); err != nil { - return nil, err + return err } err := req.SetRootContext(ctx) if err != nil { - return nil, err + return err } // Okay!!!!! NOW we can call the command. - res = root.Call(req) - + go func() { + err := root.Call(req, re) + if err != nil { + re.SetError(err, cmdkit.ErrNormal) + } + }() } - if cmd.PostRun != nil { - cmd.PostRun(req, res) + if returnCode := <-exitCh; returnCode != 0 { + err = exitErr(returnCode) } - return res, nil + return err } // commandDetails returns a command's details for the command given by |path| @@ -372,13 +407,12 @@ func commandDetails(path []string, root *cmds.Command) (*cmdDetails, error) { // find the last command in path that has a cmdDetailsMap entry cmd := root for _, cmp := range path { - var found bool - cmd, found = cmd.Subcommands[cmp] - if !found { + cmd = cmd.Subcommand(cmp) + if cmd == nil { return nil, fmt.Errorf("subcommand %s should be in root", cmp) } - if cmdDetails, found := cmdDetailsMap[cmd]; found { + if cmdDetails, found := cmdDetailsMap[strings.Join(path, "/")]; found { details = cmdDetails } } @@ -391,7 +425,7 @@ func commandDetails(path []string, root *cmds.Command) (*cmdDetails, error) { // It returns a client if the command should be executed on a daemon and nil if // it should be executed on a client. It returns an error if the command must // NOT be executed on either. -func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.Command) (cmdsHttp.Client, error) { +func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.Command) (http.Client, error) { path := req.Path() // root command. if len(path) < 1 { @@ -449,17 +483,10 @@ func commandShouldRunOnDaemon(details cmdDetails, req cmds.Request, root *cmds.C } func isClientError(err error) bool { - - // Somewhat suprisingly, the pointer cast fails to recognize commands.Error - // passed as values, so we check both. - - // cast to cmds.Error - switch e := err.(type) { - case *cmds.Error: - return e.Code == cmds.ErrClient - case cmds.Error: - return e.Code == cmds.ErrClient + if e, ok := err.(*cmdkit.Error); ok { + return e.Code == cmdkit.ErrClient } + return false } @@ -606,7 +633,7 @@ var checkIPFSWinFmt = "Otherwise check:\n\ttasklist | findstr ipfs" // getApiClient checks the repo, and the given options, checking for // a running API service. if there is one, it returns a client. // otherwise, it returns errApiNotRunning, or another error. -func getApiClient(repoPath, apiAddrStr string) (cmdsHttp.Client, error) { +func getApiClient(repoPath, apiAddrStr string) (http.Client, error) { var apiErrorFmt string switch { case osh.IsUnix(): @@ -643,13 +670,13 @@ func getApiClient(repoPath, apiAddrStr string) (cmdsHttp.Client, error) { return apiClientForAddr(addr) } -func apiClientForAddr(addr ma.Multiaddr) (cmdsHttp.Client, error) { +func apiClientForAddr(addr ma.Multiaddr) (http.Client, error) { _, host, err := manet.DialArgs(addr) if err != nil { return nil, err } - return cmdsHttp.NewClient(host), nil + return http.NewClient(host), nil } func isConnRefused(err error) bool { diff --git a/cmd/ipfs/main_test.go b/cmd/ipfs/main_test.go index 251404e17..371e8efcd 100644 --- a/cmd/ipfs/main_test.go +++ b/cmd/ipfs/main_test.go @@ -3,15 +3,12 @@ package main import ( "testing" - "github.com/ipfs/go-ipfs/commands" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) func TestIsCientErr(t *testing.T) { - t.Log("Catch both pointers and values") - if !isClientError(commands.Error{Code: commands.ErrClient}) { - t.Errorf("misidentified value") - } - if !isClientError(&commands.Error{Code: commands.ErrClient}) { - t.Errorf("misidentified pointer") + t.Log("Only catch pointers") + if !isClientError(&cmdkit.Error{Code: cmdkit.ErrClient}) { + t.Errorf("misidentified error") } } diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index 6c9410147..6d34d3a14 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -9,7 +9,6 @@ import ( "path/filepath" "syscall" - commands "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" corehttp "github.com/ipfs/go-ipfs/core/corehttp" coreunix "github.com/ipfs/go-ipfs/core/coreunix" @@ -18,8 +17,8 @@ import ( homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" + commands "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" process "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" - fsnotify "gx/ipfs/QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv/fsnotify.v1" ) diff --git a/cmd/seccat/seccat.go b/cmd/seccat/seccat.go index 88c492616..e1a06ab02 100644 --- a/cmd/seccat/seccat.go +++ b/cmd/seccat/seccat.go @@ -9,6 +9,7 @@ package main import ( + "context" "errors" "flag" "fmt" @@ -18,7 +19,6 @@ import ( "os/signal" "syscall" - context "context" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" diff --git a/commands/argument.go b/commands/argument.go deleted file mode 100644 index afc06e573..000000000 --- a/commands/argument.go +++ /dev/null @@ -1,56 +0,0 @@ -package commands - -type ArgumentType int - -const ( - ArgString ArgumentType = iota - ArgFile -) - -type Argument struct { - Name string - Type ArgumentType - Required bool // error if no value is specified - Variadic bool // unlimited values can be specfied - SupportsStdin bool // can accept stdin as a value - Recursive bool // supports recursive file adding (with '-r' flag) - Description string -} - -func StringArg(name string, required, variadic bool, description string) Argument { - return Argument{ - Name: name, - Type: ArgString, - Required: required, - Variadic: variadic, - Description: description, - } -} - -func FileArg(name string, required, variadic bool, description string) Argument { - return Argument{ - Name: name, - Type: ArgFile, - Required: required, - Variadic: variadic, - Description: description, - } -} - -// TODO: modifiers might need a different API? -// e.g. passing enum values into arg constructors variadically -// (`FileArg("file", ArgRequired, ArgStdin, ArgRecursive)`) - -func (a Argument) EnableStdin() Argument { - a.SupportsStdin = true - return a -} - -func (a Argument) EnableRecursive() Argument { - if a.Type != ArgFile { - panic("Only FileArgs can enable recursive") - } - - a.Recursive = true - return a -} diff --git a/commands/channelmarshaler.go b/commands/channelmarshaler.go index 0c731ee8c..4564b537b 100644 --- a/commands/channelmarshaler.go +++ b/commands/channelmarshaler.go @@ -1,6 +1,8 @@ package commands -import "io" +import ( + "io" +) type ChannelMarshaler struct { Channel <-chan interface{} diff --git a/commands/cli/cmd_suggestion.go b/commands/cli/cmd_suggestion.go index 8b3dae063..e40ad6d84 100644 --- a/commands/cli/cmd_suggestion.go +++ b/commands/cli/cmd_suggestion.go @@ -40,7 +40,7 @@ func suggestUnknownCmd(args []string, root *cmds.Command) []string { var sFinal []string const MIN_LEVENSHTEIN = 3 - var options levenshtein.Options = levenshtein.Options{ + var options = levenshtein.Options{ InsCost: 1, DelCost: 3, SubCost: 2, @@ -50,7 +50,7 @@ func suggestUnknownCmd(args []string, root *cmds.Command) []string { } // Start with a simple strings.Contains check - for name, _ := range root.Subcommands { + for name := range root.Subcommands { if strings.Contains(arg, name) { suggestions = append(suggestions, name) } @@ -61,7 +61,7 @@ func suggestUnknownCmd(args []string, root *cmds.Command) []string { return suggestions } - for name, _ := range root.Subcommands { + for name := range root.Subcommands { lev := levenshtein.DistanceForStrings([]rune(arg), []rune(name), options) if lev <= MIN_LEVENSHTEIN { sortableSuggestions = append(sortableSuggestions, &suggestion{name, lev}) @@ -83,7 +83,7 @@ func printSuggestions(inputs []string, root *cmds.Command) (err error) { } else if len(suggestions) > 0 { err = fmt.Errorf("Unknown Command \"%s\"\n\nDid you mean this?\n\n\t%s", inputs[0], suggestions[0]) } else { - err = fmt.Errorf("Unknown Command \"%s\"\n", inputs[0]) + err = fmt.Errorf("Unknown Command %q", inputs[0]) } return } diff --git a/commands/cli/helptext.go b/commands/cli/helptext.go index 7d43e3e2e..ae9ce7201 100644 --- a/commands/cli/helptext.go +++ b/commands/cli/helptext.go @@ -8,6 +8,7 @@ import ( "text/template" cmds "github.com/ipfs/go-ipfs/commands" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) const ( @@ -231,13 +232,13 @@ func generateSynopsis(cmd *cmds.Command, path string) string { if len(n) > 1 { pre = "--" } - if opt.Type() == cmds.Bool && opt.DefaultVal() == true { + if opt.Type() == cmdkit.Bool && opt.DefaultVal() == true { pre = "--" sopt = fmt.Sprintf("%s%s=false", pre, n) break } else { if i == 0 { - if opt.Type() == cmds.Bool { + if opt.Type() == cmdkit.Bool { sopt = fmt.Sprintf("%s%s", pre, n) } else { sopt = fmt.Sprintf("%s%s=<%s>", pre, n, valopt) @@ -283,14 +284,14 @@ func argumentText(cmd *cmds.Command) []string { func optionFlag(flag string) string { if len(flag) == 1 { return fmt.Sprintf(shortFlag, flag) - } else { - return fmt.Sprintf(longFlag, flag) } + + return fmt.Sprintf(longFlag, flag) } func optionText(cmd ...*cmds.Command) []string { // get a slice of the options we want to list out - options := make([]cmds.Option, 0) + options := make([]cmdkit.Option, 0) for _, c := range cmd { options = append(options, c.Options...) } @@ -387,7 +388,7 @@ func usageText(cmd *cmds.Command) string { return s } -func argUsageText(arg cmds.Argument) string { +func argUsageText(arg cmdkit.Argument) string { s := arg.Name if arg.Required { diff --git a/commands/cli/helptext_test.go b/commands/cli/helptext_test.go index aa8361f99..43bcf98b8 100644 --- a/commands/cli/helptext_test.go +++ b/commands/cli/helptext_test.go @@ -5,18 +5,20 @@ import ( "testing" cmds "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) func TestSynopsisGenerator(t *testing.T) { command := &cmds.Command{ - Arguments: []cmds.Argument{ - cmds.StringArg("required", true, false, ""), - cmds.StringArg("variadic", false, true, ""), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("required", true, false, ""), + cmdkit.StringArg("variadic", false, true, ""), }, - Options: []cmds.Option{ - cmds.StringOption("opt", "o", "Option"), + Options: []cmdkit.Option{ + cmdkit.StringOption("opt", "o", "Option"), }, - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ SynopsisOptionsValues: map[string]string{ "opt": "OPTION", }, diff --git a/commands/cli/parse.go b/commands/cli/parse.go index 6d1504456..c6bc1e028 100644 --- a/commands/cli/parse.go +++ b/commands/cli/parse.go @@ -10,8 +10,8 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" - files "github.com/ipfs/go-ipfs/commands/files" - + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" osh "gx/ipfs/QmXuBJ7DR6k3rmUEKtvVMhwjmXDuJgXXPUt4LQXKBMsU93/go-os-helper" @@ -63,14 +63,14 @@ func Parse(input []string, stdin *os.File, root *cmds.Command) (cmds.Request, *c return req, cmd, path, err } -func ParseArgs(req cmds.Request, inputs []string, stdin *os.File, argDefs []cmds.Argument, root *cmds.Command) ([]string, []files.File, error) { +func ParseArgs(req cmds.Request, inputs []string, stdin *os.File, argDefs []cmdkit.Argument, root *cmds.Command) ([]string, []files.File, error) { var err error // if -r is provided, and it is associated with the package builtin // recursive path option, allow recursive file paths - recursiveOpt := req.Option(cmds.RecShort) + recursiveOpt := req.Option(cmdkit.RecShort) recursive := false - if recursiveOpt != nil && recursiveOpt.Definition() == cmds.OptionRecursivePath { + if recursiveOpt != nil && recursiveOpt.Definition() == cmdkit.OptionRecursivePath { recursive, _, err = recursiveOpt.Bool() if err != nil { return nil, nil, u.ErrCast() @@ -99,7 +99,7 @@ func parseOpts(args []string, root *cmds.Command) ( ) { path = make([]string, 0, len(args)) stringVals = make([]string, 0, len(args)) - optDefs := map[string]cmds.Option{} + optDefs := map[string]cmdkit.Option{} opts = map[string]interface{}{} cmd = root @@ -121,7 +121,7 @@ func parseOpts(args []string, root *cmds.Command) ( // eg. ipfs -r means disregard since there is no '=' // mustUse == false in the above situation //arg == nil implies the flag was specified without an argument - if optDef.Type() == cmds.Bool { + if optDef.Type() == cmdkit.Bool { if arg == nil || !mustUse { opts[name] = true return false, nil @@ -256,7 +256,7 @@ func parseOpts(args []string, root *cmds.Command) ( const msgStdinInfo = "ipfs: Reading from %s; send Ctrl-d to stop." -func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursive, hidden bool, root *cmds.Command) ([]string, []files.File, error) { +func parseArgs(inputs []string, stdin *os.File, argDefs []cmdkit.Argument, recursive, hidden bool, root *cmds.Command) ([]string, []files.File, error) { // ignore stdin on Windows if osh.IsWindows() { stdin = nil @@ -275,7 +275,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi // below to parse stdin. numInputs := len(inputs) if len(argDefs) > 0 && argDefs[len(argDefs)-1].SupportsStdin && stdin != nil { - numInputs += 1 + numInputs++ } // if we have more arg values provided than argument definitions, @@ -305,7 +305,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi fillingVariadic := argDefIndex+1 > len(argDefs) switch argDef.Type { - case cmds.ArgString: + case cmdkit.ArgString: if len(inputs) > 0 { stringArgs, inputs = append(stringArgs, inputs[0]), inputs[1:] } else if stdin != nil && argDef.SupportsStdin && !fillingVariadic { @@ -314,7 +314,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi stdin = nil } } - case cmds.ArgFile: + case cmdkit.ArgFile: if len(inputs) > 0 { // treat stringArg values as file paths fpath := inputs[0] @@ -367,7 +367,7 @@ func parseArgs(inputs []string, stdin *os.File, argDefs []cmds.Argument, recursi func filesMapToSortedArr(fs map[string]files.File) []files.File { var names []string - for name, _ := range fs { + for name := range fs { names = append(names, name) } @@ -381,7 +381,7 @@ func filesMapToSortedArr(fs map[string]files.File) []files.File { return out } -func getArgDef(i int, argDefs []cmds.Argument) *cmds.Argument { +func getArgDef(i int, argDefs []cmdkit.Argument) *cmdkit.Argument { if i < len(argDefs) { // get the argument definition (usually just argDefs[i]) return &argDefs[i] @@ -399,7 +399,7 @@ const notRecursiveFmtStr = "'%s' is a directory, use the '-%s' flag to specify d const dirNotSupportedFmtStr = "Invalid path '%s', argument '%s' does not support directories" const winDriveLetterFmtStr = "%q is a drive letter, not a drive path" -func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (files.File, error) { +func appendFile(fpath string, argDef *cmdkit.Argument, recursive, hidden bool) (files.File, error) { // resolve Windows relative dot paths like `X:.\somepath` if osh.IsWindows() { if len(fpath) >= 3 && fpath[1:3] == ":." { @@ -435,7 +435,7 @@ func appendFile(fpath string, argDef *cmds.Argument, recursive, hidden bool) (fi return nil, fmt.Errorf(dirNotSupportedFmtStr, fpath, argDef.Name) } if !recursive { - return nil, fmt.Errorf(notRecursiveFmtStr, fpath, cmds.RecShort) + return nil, fmt.Errorf(notRecursiveFmtStr, fpath, cmdkit.RecShort) } } diff --git a/commands/cli/parse_test.go b/commands/cli/parse_test.go index 107116fba..751e3e8b0 100644 --- a/commands/cli/parse_test.go +++ b/commands/cli/parse_test.go @@ -9,6 +9,8 @@ import ( "testing" "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type kvs map[string]interface{} @@ -68,9 +70,9 @@ func TestSameWords(t *testing.T) { func TestOptionParsing(t *testing.T) { subCmd := &commands.Command{} cmd := &commands.Command{ - Options: []commands.Option{ - commands.StringOption("string", "s", "a string"), - commands.BoolOption("bool", "b", "a bool"), + Options: []cmdkit.Option{ + cmdkit.StringOption("string", "s", "a string"), + cmdkit.BoolOption("bool", "b", "a bool"), }, Subcommands: map[string]*commands.Command{ "test": subCmd, @@ -145,58 +147,58 @@ func TestArgumentParsing(t *testing.T) { Subcommands: map[string]*commands.Command{ "noarg": {}, "onearg": { - Arguments: []commands.Argument{ - commands.StringArg("a", true, false, "some arg"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, false, "some arg"), }, }, "twoargs": { - Arguments: []commands.Argument{ - commands.StringArg("a", true, false, "some arg"), - commands.StringArg("b", true, false, "another arg"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, false, "some arg"), + cmdkit.StringArg("b", true, false, "another arg"), }, }, "variadic": { - Arguments: []commands.Argument{ - commands.StringArg("a", true, true, "some arg"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, true, "some arg"), }, }, "optional": { - Arguments: []commands.Argument{ - commands.StringArg("b", false, true, "another arg"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("b", false, true, "another arg"), }, }, "optionalsecond": { - Arguments: []commands.Argument{ - commands.StringArg("a", true, false, "some arg"), - commands.StringArg("b", false, false, "another arg"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, false, "some arg"), + cmdkit.StringArg("b", false, false, "another arg"), }, }, "reversedoptional": { - Arguments: []commands.Argument{ - commands.StringArg("a", false, false, "some arg"), - commands.StringArg("b", true, false, "another arg"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", false, false, "some arg"), + cmdkit.StringArg("b", true, false, "another arg"), }, }, "stdinenabled": { - Arguments: []commands.Argument{ - commands.StringArg("a", true, true, "some arg").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, true, "some arg").EnableStdin(), }, }, "stdinenabled2args": &commands.Command{ - Arguments: []commands.Argument{ - commands.StringArg("a", true, false, "some arg"), - commands.StringArg("b", true, true, "another arg").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, false, "some arg"), + cmdkit.StringArg("b", true, true, "another arg").EnableStdin(), }, }, "stdinenablednotvariadic": &commands.Command{ - Arguments: []commands.Argument{ - commands.StringArg("a", true, false, "some arg").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, false, "some arg").EnableStdin(), }, }, "stdinenablednotvariadic2args": &commands.Command{ - Arguments: []commands.Argument{ - commands.StringArg("a", true, false, "some arg"), - commands.StringArg("b", true, false, "another arg").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("a", true, false, "some arg"), + cmdkit.StringArg("b", true, false, "another arg").EnableStdin(), }, }, }, diff --git a/commands/command.go b/commands/command.go index 700332acc..841ed6bcd 100644 --- a/commands/command.go +++ b/commands/command.go @@ -15,6 +15,7 @@ import ( "reflect" "github.com/ipfs/go-ipfs/path" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ) @@ -32,28 +33,11 @@ type Marshaler func(Response) (io.Reader, error) // (or an error on failure) type MarshalerMap map[EncodingType]Marshaler -// HelpText is a set of strings used to generate command help text. The help -// text follows formats similar to man pages, but not exactly the same. -type HelpText struct { - // required - Tagline string // used in - ShortDescription string // used in DESCRIPTION - SynopsisOptionsValues map[string]string // mappings for synopsis generator - - // optional - whole section overrides - Usage string // overrides USAGE section - LongDescription string // overrides DESCRIPTION section - Options string // overrides OPTIONS section - Arguments string // overrides ARGUMENTS section - Subcommands string // overrides SUBCOMMANDS section - Synopsis string // overrides SYNOPSIS field -} - // Command is a runnable command, with input arguments and options (flags). // It can also have Subcommands, to group units of work into sets. type Command struct { - Options []Option - Arguments []Argument + Options []cmdkit.Option + Arguments []cmdkit.Argument PreRun func(req Request) error // Run is the function that processes the request to generate a response. @@ -63,7 +47,7 @@ type Command struct { Run Function PostRun Function Marshalers map[EncodingType]Marshaler - Helptext HelpText + Helptext cmdkit.HelpText // External denotes that a command is actually an external binary. // fewer checks and validations will be performed on such commands. @@ -91,25 +75,25 @@ func (c *Command) Call(req Request) Response { cmds, err := c.Resolve(req.Path()) if err != nil { - res.SetError(err, ErrClient) + res.SetError(err, cmdkit.ErrClient) return res } cmd := cmds[len(cmds)-1] if cmd.Run == nil { - res.SetError(ErrNotCallable, ErrClient) + res.SetError(ErrNotCallable, cmdkit.ErrClient) return res } err = cmd.CheckArguments(req) if err != nil { - res.SetError(err, ErrClient) + res.SetError(err, cmdkit.ErrClient) return res } err = req.ConvertOptions() if err != nil { - res.SetError(err, ErrClient) + res.SetError(err, cmdkit.ErrClient) return res } @@ -145,7 +129,7 @@ func (c *Command) Call(req Request) Response { expectedType := reflect.TypeOf(cmd.Type) if actualType != expectedType { - res.SetError(ErrIncorrectType, ErrNormal) + res.SetError(ErrIncorrectType, cmdkit.ErrNormal) return res } } @@ -183,8 +167,8 @@ func (c *Command) Get(path []string) (*Command, error) { } // GetOptions returns the options in the given path of commands -func (c *Command) GetOptions(path []string) (map[string]Option, error) { - options := make([]Option, 0, len(c.Options)) +func (c *Command) GetOptions(path []string) (map[string]cmdkit.Option, error) { + options := make([]cmdkit.Option, 0, len(c.Options)) cmds, err := c.Resolve(path) if err != nil { @@ -196,7 +180,7 @@ func (c *Command) GetOptions(path []string) (map[string]Option, error) { options = append(options, cmd.Options...) } - optionsMap := make(map[string]Option) + optionsMap := make(map[string]cmdkit.Option) for _, opt := range options { for _, name := range opt.Names() { if _, found := optionsMap[name]; found { @@ -227,7 +211,7 @@ func (c *Command) CheckArguments(req Request) error { // skip optional argument definitions if there aren't // sufficient remaining values if len(args)-valueIndex <= numRequired && !argDef.Required || - argDef.Type == ArgFile { + argDef.Type == cmdkit.ArgFile { continue } @@ -290,7 +274,7 @@ func (c *Command) ProcessHelp() { // checkArgValue returns an error if a given arg value is not valid for the // given Argument -func checkArgValue(v string, found bool, def Argument) error { +func checkArgValue(v string, found bool, def cmdkit.Argument) error { if def.Variadic && def.SupportsStdin { return nil } @@ -303,5 +287,17 @@ func checkArgValue(v string, found bool, def Argument) error { } func ClientError(msg string) error { - return &Error{Code: ErrClient, Message: msg} + return &cmdkit.Error{Code: cmdkit.ErrClient, Message: msg} +} + +// global options, added to every command +var globalOptions = []cmdkit.Option{ + cmdkit.OptionEncodingType, + cmdkit.OptionStreamChannels, + cmdkit.OptionTimeout, +} + +// the above array of Options, wrapped in a Command +var globalCommand = &Command{ + Options: globalOptions, } diff --git a/commands/command_test.go b/commands/command_test.go index a61de267b..7360377b0 100644 --- a/commands/command_test.go +++ b/commands/command_test.go @@ -1,15 +1,19 @@ package commands -import "testing" +import ( + "testing" + + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" +) func noop(req Request, res Response) { } func TestOptionValidation(t *testing.T) { cmd := Command{ - Options: []Option{ - IntOption("b", "beep", "enables beeper"), - StringOption("B", "boop", "password for booper"), + Options: []cmdkit.Option{ + cmdkit.IntOption("b", "beep", "enables beeper"), + cmdkit.StringOption("B", "boop", "password for booper"), }, Run: noop, } @@ -54,7 +58,7 @@ func TestOptionValidation(t *testing.T) { } req, _ = NewRequest(nil, nil, nil, nil, nil, opts) - req.SetOption(EncShort, "json") + req.SetOption(cmdkit.EncShort, "json") res = cmd.Call(req) if res.Error() != nil { t.Error("Should have passed") @@ -91,15 +95,15 @@ func TestOptionValidation(t *testing.T) { func TestRegistration(t *testing.T) { cmdA := &Command{ - Options: []Option{ - IntOption("beep", "number of beeps"), + Options: []cmdkit.Option{ + cmdkit.IntOption("beep", "number of beeps"), }, Run: noop, } cmdB := &Command{ - Options: []Option{ - IntOption("beep", "number of beeps"), + Options: []cmdkit.Option{ + cmdkit.IntOption("beep", "number of beeps"), }, Run: noop, Subcommands: map[string]*Command{ @@ -108,8 +112,8 @@ func TestRegistration(t *testing.T) { } cmdC := &Command{ - Options: []Option{ - StringOption("encoding", "data encoding type"), + Options: []cmdkit.Option{ + cmdkit.StringOption("encoding", "data encoding type"), }, Run: noop, } @@ -173,12 +177,12 @@ func TestWalking(t *testing.T) { func TestHelpProcessing(t *testing.T) { cmdB := &Command{ - Helptext: HelpText{ + Helptext: cmdkit.HelpText{ ShortDescription: "This is other short", }, } cmdA := &Command{ - Helptext: HelpText{ + Helptext: cmdkit.HelpText{ ShortDescription: "This is short", }, Subcommands: map[string]*Command{ diff --git a/commands/files/file.go b/commands/files/file.go deleted file mode 100644 index 949180716..000000000 --- a/commands/files/file.go +++ /dev/null @@ -1,62 +0,0 @@ -package files - -import ( - "errors" - "io" - "os" -) - -var ( - ErrNotDirectory = errors.New("Couldn't call NextFile(), this isn't a directory") - ErrNotReader = errors.New("This file is a directory, can't use Reader functions") -) - -// File is an interface that provides functionality for handling -// files/directories as values that can be supplied to commands. For -// directories, child files are accessed serially by calling `NextFile()`. -type File interface { - // Files implement ReadCloser, but can only be read from or closed if - // they are not directories - io.ReadCloser - - // FileName returns a filename associated with this file - FileName() string - - // FullPath returns the full path used when adding this file - FullPath() string - - // IsDirectory returns true if the File is a directory (and therefore - // supports calling `NextFile`) and false if the File is a normal file - // (and therefor supports calling `Read` and `Close`) - IsDirectory() bool - - // NextFile returns the next child file available (if the File is a - // directory). It will return (nil, io.EOF) if no more files are - // available. If the file is a regular file (not a directory), NextFile - // will return a non-nil error. - NextFile() (File, error) -} - -type StatFile interface { - File - - Stat() os.FileInfo -} - -type PeekFile interface { - SizeFile - - Peek(n int) File - Length() int -} - -type SizeFile interface { - File - - Size() (int64, error) -} - -type FileInfo interface { - AbsPath() string - Stat() os.FileInfo -} diff --git a/commands/files/file_test.go b/commands/files/file_test.go deleted file mode 100644 index 8c4bcb263..000000000 --- a/commands/files/file_test.go +++ /dev/null @@ -1,203 +0,0 @@ -package files - -import ( - "io" - "io/ioutil" - "mime/multipart" - "strings" - "testing" -) - -func TestSliceFiles(t *testing.T) { - name := "testname" - files := []File{ - NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil), - NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), - NewReaderFile("boop.txt", "boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil), - } - buf := make([]byte, 20) - - sf := NewSliceFile(name, name, files) - - if !sf.IsDirectory() { - t.Fatal("SliceFile should always be a directory") - } - - if n, err := sf.Read(buf); n > 0 || err != io.EOF { - t.Fatal("Shouldn't be able to read data from a SliceFile") - } - - if err := sf.Close(); err != ErrNotReader { - t.Fatal("Shouldn't be able to call `Close` on a SliceFile") - } - - file, err := sf.NextFile() - if file == nil || err != nil { - t.Fatal("Expected a file and nil error") - } - read, err := file.Read(buf) - if read != 11 || err != nil { - t.Fatal("NextFile got a file in the wrong order") - } - - file, err = sf.NextFile() - if file == nil || err != nil { - t.Fatal("Expected a file and nil error") - } - file, err = sf.NextFile() - if file == nil || err != nil { - t.Fatal("Expected a file and nil error") - } - - file, err = sf.NextFile() - if file != nil || err != io.EOF { - t.Fatal("Expected a nil file and io.EOF") - } -} - -func TestReaderFiles(t *testing.T) { - message := "beep boop" - rf := NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(message)), nil) - buf := make([]byte, len(message)) - - if rf.IsDirectory() { - t.Fatal("ReaderFile should never be a directory") - } - file, err := rf.NextFile() - if file != nil || err != ErrNotDirectory { - t.Fatal("Expected a nil file and ErrNotDirectory") - } - - if n, err := rf.Read(buf); n == 0 || err != nil { - t.Fatal("Expected to be able to read") - } - if err := rf.Close(); err != nil { - t.Fatal("Should be able to close") - } - if n, err := rf.Read(buf); n != 0 || err != io.EOF { - t.Fatal("Expected EOF when reading after close") - } -} - -func TestMultipartFiles(t *testing.T) { - data := ` ---Boundary! -Content-Type: text/plain -Content-Disposition: file; filename="name" -Some-Header: beep - -beep ---Boundary! -Content-Type: application/x-directory -Content-Disposition: file; filename="dir" - ---Boundary! -Content-Type: text/plain -Content-Disposition: file; filename="dir/nested" - -some content ---Boundary! -Content-Type: application/symlink -Content-Disposition: file; filename="dir/simlynk" - -anotherfile ---Boundary!-- - -` - - reader := strings.NewReader(data) - mpReader := multipart.NewReader(reader, "Boundary!") - buf := make([]byte, 20) - - // test properties of a file created from the first part - part, err := mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err := NewFileFromPart(part) - if mpf == nil || err != nil { - t.Fatal("Expected non-nil MultipartFile, nil error") - } - if mpf.IsDirectory() { - t.Fatal("Expected file to not be a directory") - } - if mpf.FileName() != "name" { - t.Fatal("Expected filename to be \"name\"") - } - if file, err := mpf.NextFile(); file != nil || err != ErrNotDirectory { - t.Fatal("Expected a nil file and ErrNotDirectory") - } - if n, err := mpf.Read(buf); n != 4 || err != io.EOF && err != nil { - t.Fatal("Expected to be able to read 4 bytes: ", n, err) - } - if err := mpf.Close(); err != nil { - t.Fatal("Expected to be able to close file") - } - - // test properties of file created from second part (directory) - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - if mpf == nil || err != nil { - t.Fatal("Expected non-nil MultipartFile, nil error") - } - if !mpf.IsDirectory() { - t.Fatal("Expected file to be a directory") - } - if mpf.FileName() != "dir" { - t.Fatal("Expected filename to be \"dir\"") - } - if n, err := mpf.Read(buf); n > 0 || err != ErrNotReader { - t.Fatal("Shouldn't be able to call `Read` on a directory") - } - if err := mpf.Close(); err != ErrNotReader { - t.Fatal("Shouldn't be able to call `Close` on a directory") - } - - // test properties of file created from third part (nested file) - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - if mpf == nil || err != nil { - t.Fatal("Expected non-nil MultipartFile, nil error") - } - if mpf.IsDirectory() { - t.Fatal("Expected file, got directory") - } - if mpf.FileName() != "dir/nested" { - t.Fatalf("Expected filename to be \"nested\", got %s", mpf.FileName()) - } - if n, err := mpf.Read(buf); n != 12 || err != io.EOF && err != nil { - t.Fatalf("expected to be able to read 12 bytes from file: %s (got %d)", err, n) - } - if err := mpf.Close(); err != nil { - t.Fatalf("should be able to close file: %s", err) - } - - // test properties of symlink created from fourth part (symlink) - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - if mpf == nil || err != nil { - t.Fatal("Expected non-nil MultipartFile, nil error") - } - if mpf.IsDirectory() { - t.Fatal("Expected file to be a symlink") - } - if mpf.FileName() != "dir/simlynk" { - t.Fatal("Expected filename to be \"dir/simlynk\"") - } - slink, ok := mpf.(*Symlink) - if !ok { - t.Fatalf("expected file to be a symlink") - } - if slink.Target != "anotherfile" { - t.Fatal("expected link to point to anotherfile") - } -} diff --git a/commands/files/is_hidden.go b/commands/files/is_hidden.go deleted file mode 100644 index b0360685b..000000000 --- a/commands/files/is_hidden.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !windows - -package files - -import ( - "path/filepath" - "strings" -) - -func IsHidden(f File) bool { - - fName := filepath.Base(f.FileName()) - - if strings.HasPrefix(fName, ".") && len(fName) > 1 { - return true - } - - return false -} diff --git a/commands/files/is_hidden_windows.go b/commands/files/is_hidden_windows.go deleted file mode 100644 index 896437cf1..000000000 --- a/commands/files/is_hidden_windows.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build windows - -package files - -import ( - "path/filepath" - "strings" - "syscall" -) - -func IsHidden(f File) bool { - - fName := filepath.Base(f.FileName()) - - if strings.HasPrefix(fName, ".") && len(fName) > 1 { - return true - } - - p, e := syscall.UTF16PtrFromString(f.FullPath()) - if e != nil { - return false - } - - attrs, e := syscall.GetFileAttributes(p) - if e != nil { - return false - } - return attrs&syscall.FILE_ATTRIBUTE_HIDDEN != 0 -} diff --git a/commands/files/linkfile.go b/commands/files/linkfile.go deleted file mode 100644 index 18466f4bd..000000000 --- a/commands/files/linkfile.go +++ /dev/null @@ -1,50 +0,0 @@ -package files - -import ( - "io" - "os" - "strings" -) - -type Symlink struct { - name string - path string - Target string - stat os.FileInfo - - reader io.Reader -} - -func NewLinkFile(name, path, target string, stat os.FileInfo) File { - return &Symlink{ - name: name, - path: path, - Target: target, - stat: stat, - reader: strings.NewReader(target), - } -} - -func (lf *Symlink) IsDirectory() bool { - return false -} - -func (lf *Symlink) NextFile() (File, error) { - return nil, io.EOF -} - -func (f *Symlink) FileName() string { - return f.name -} - -func (f *Symlink) Close() error { - return nil -} - -func (f *Symlink) FullPath() string { - return f.path -} - -func (f *Symlink) Read(b []byte) (int, error) { - return f.reader.Read(b) -} diff --git a/commands/files/multipartfile.go b/commands/files/multipartfile.go deleted file mode 100644 index 073569e8a..000000000 --- a/commands/files/multipartfile.go +++ /dev/null @@ -1,115 +0,0 @@ -package files - -import ( - "io" - "io/ioutil" - "mime" - "mime/multipart" - "net/url" -) - -const ( - multipartFormdataType = "multipart/form-data" - - applicationDirectory = "application/x-directory" - applicationSymlink = "application/symlink" - applicationFile = "application/octet-stream" - - contentTypeHeader = "Content-Type" -) - -// MultipartFile implements File, and is created from a `multipart.Part`. -// It can be either a directory or file (checked by calling `IsDirectory()`). -type MultipartFile struct { - File - - Part *multipart.Part - Reader *multipart.Reader - Mediatype string -} - -func NewFileFromPart(part *multipart.Part) (File, error) { - f := &MultipartFile{ - Part: part, - } - - contentType := part.Header.Get(contentTypeHeader) - switch contentType { - case applicationSymlink: - out, err := ioutil.ReadAll(part) - if err != nil { - return nil, err - } - - return &Symlink{ - Target: string(out), - name: f.FileName(), - }, nil - case applicationFile: - return &ReaderFile{ - reader: part, - filename: f.FileName(), - abspath: part.Header.Get("abspath"), - fullpath: f.FullPath(), - }, nil - } - - var err error - f.Mediatype, _, err = mime.ParseMediaType(contentType) - if err != nil { - return nil, err - } - - return f, nil -} - -func (f *MultipartFile) IsDirectory() bool { - return f.Mediatype == multipartFormdataType || f.Mediatype == applicationDirectory -} - -func (f *MultipartFile) NextFile() (File, error) { - if !f.IsDirectory() { - return nil, ErrNotDirectory - } - if f.Reader != nil { - part, err := f.Reader.NextPart() - if err != nil { - return nil, err - } - - return NewFileFromPart(part) - } - - return nil, io.EOF -} - -func (f *MultipartFile) FileName() string { - if f == nil || f.Part == nil { - return "" - } - - filename, err := url.QueryUnescape(f.Part.FileName()) - if err != nil { - // if there is a unescape error, just treat the name as unescaped - return f.Part.FileName() - } - return filename -} - -func (f *MultipartFile) FullPath() string { - return f.FileName() -} - -func (f *MultipartFile) Read(p []byte) (int, error) { - if f.IsDirectory() { - return 0, ErrNotReader - } - return f.Part.Read(p) -} - -func (f *MultipartFile) Close() error { - if f.IsDirectory() { - return ErrNotReader - } - return f.Part.Close() -} diff --git a/commands/files/readerfile.go b/commands/files/readerfile.go deleted file mode 100644 index 863641479..000000000 --- a/commands/files/readerfile.go +++ /dev/null @@ -1,70 +0,0 @@ -package files - -import ( - "errors" - "io" - "os" - "path/filepath" -) - -// ReaderFile is a implementation of File created from an `io.Reader`. -// ReaderFiles are never directories, and can be read from and closed. -type ReaderFile struct { - filename string - fullpath string - abspath string - reader io.ReadCloser - stat os.FileInfo -} - -func NewReaderFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile { - return &ReaderFile{filename, path, path, reader, stat} -} - -func NewReaderPathFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) (*ReaderFile, error) { - abspath, err := filepath.Abs(path) - if err != nil { - return nil, err - } - - return &ReaderFile{filename, path, abspath, reader, stat}, nil -} - -func (f *ReaderFile) IsDirectory() bool { - return false -} - -func (f *ReaderFile) NextFile() (File, error) { - return nil, ErrNotDirectory -} - -func (f *ReaderFile) FileName() string { - return f.filename -} - -func (f *ReaderFile) FullPath() string { - return f.fullpath -} - -func (f *ReaderFile) AbsPath() string { - return f.abspath -} - -func (f *ReaderFile) Read(p []byte) (int, error) { - return f.reader.Read(p) -} - -func (f *ReaderFile) Close() error { - return f.reader.Close() -} - -func (f *ReaderFile) Stat() os.FileInfo { - return f.stat -} - -func (f *ReaderFile) Size() (int64, error) { - if f.stat == nil { - return 0, errors.New("File size unknown") - } - return f.stat.Size(), nil -} diff --git a/commands/files/serialfile.go b/commands/files/serialfile.go deleted file mode 100644 index b17d14af1..000000000 --- a/commands/files/serialfile.go +++ /dev/null @@ -1,154 +0,0 @@ -package files - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "syscall" -) - -// serialFile implements File, and reads from a path on the OS filesystem. -// No more than one file will be opened at a time (directories will advance -// to the next file when NextFile() is called). -type serialFile struct { - name string - path string - files []os.FileInfo - stat os.FileInfo - current *File - handleHiddenFiles bool -} - -func NewSerialFile(name, path string, hidden bool, stat os.FileInfo) (File, error) { - - switch mode := stat.Mode(); { - case mode.IsRegular(): - file, err := os.Open(path) - if err != nil { - return nil, err - } - return NewReaderPathFile(name, path, file, stat) - case mode.IsDir(): - // for directories, stat all of the contents first, so we know what files to - // open when NextFile() is called - contents, err := ioutil.ReadDir(path) - if err != nil { - return nil, err - } - return &serialFile{name, path, contents, stat, nil, hidden}, nil - case mode&os.ModeSymlink != 0: - target, err := os.Readlink(path) - if err != nil { - return nil, err - } - return NewLinkFile(name, path, target, stat), nil - default: - return nil, fmt.Errorf("Unrecognized file type for %s: %s", name, mode.String()) - } -} - -func (f *serialFile) IsDirectory() bool { - // non-directories get created as a ReaderFile, so serialFiles should only - // represent directories - return true -} - -func (f *serialFile) NextFile() (File, error) { - // if a file was opened previously, close it - err := f.Close() - if err != nil { - switch err2 := err.(type) { - case *os.PathError: - if err2.Err != os.ErrClosed { - return nil, err - } - default: - return nil, err - } - } - - // if there aren't any files left in the root directory, we're done - if len(f.files) == 0 { - return nil, io.EOF - } - - stat := f.files[0] - f.files = f.files[1:] - - for !f.handleHiddenFiles && strings.HasPrefix(stat.Name(), ".") { - if len(f.files) == 0 { - return nil, io.EOF - } - - stat = f.files[0] - f.files = f.files[1:] - } - - // open the next file - fileName := filepath.ToSlash(filepath.Join(f.name, stat.Name())) - filePath := filepath.ToSlash(filepath.Join(f.path, stat.Name())) - - // recursively call the constructor on the next file - // if it's a regular file, we will open it as a ReaderFile - // if it's a directory, files in it will be opened serially - sf, err := NewSerialFile(fileName, filePath, f.handleHiddenFiles, stat) - if err != nil { - return nil, err - } - - f.current = &sf - - return sf, nil -} - -func (f *serialFile) FileName() string { - return f.name -} - -func (f *serialFile) FullPath() string { - return f.path -} - -func (f *serialFile) Read(p []byte) (int, error) { - return 0, io.EOF -} - -func (f *serialFile) Close() error { - // close the current file if there is one - if f.current != nil { - err := (*f.current).Close() - // ignore EINVAL error, the file might have already been closed - if err != nil && err != syscall.EINVAL { - return err - } - } - - return nil -} - -func (f *serialFile) Stat() os.FileInfo { - return f.stat -} - -func (f *serialFile) Size() (int64, error) { - if !f.stat.IsDir() { - return f.stat.Size(), nil - } - - var du int64 - err := filepath.Walk(f.FullPath(), func(p string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if fi != nil && fi.Mode()&(os.ModeSymlink|os.ModeNamedPipe) == 0 { - du += fi.Size() - } - return nil - }) - - return du, err -} diff --git a/commands/files/slicefile.go b/commands/files/slicefile.go deleted file mode 100644 index 8d18dcaa3..000000000 --- a/commands/files/slicefile.go +++ /dev/null @@ -1,76 +0,0 @@ -package files - -import ( - "errors" - "io" -) - -// SliceFile implements File, and provides simple directory handling. -// It contains children files, and is created from a `[]File`. -// SliceFiles are always directories, and can't be read from or closed. -type SliceFile struct { - filename string - path string - files []File - n int -} - -func NewSliceFile(filename, path string, files []File) *SliceFile { - return &SliceFile{filename, path, files, 0} -} - -func (f *SliceFile) IsDirectory() bool { - return true -} - -func (f *SliceFile) NextFile() (File, error) { - if f.n >= len(f.files) { - return nil, io.EOF - } - file := f.files[f.n] - f.n++ - return file, nil -} - -func (f *SliceFile) FileName() string { - return f.filename -} - -func (f *SliceFile) FullPath() string { - return f.path -} - -func (f *SliceFile) Read(p []byte) (int, error) { - return 0, io.EOF -} - -func (f *SliceFile) Close() error { - return ErrNotReader -} - -func (f *SliceFile) Peek(n int) File { - return f.files[n] -} - -func (f *SliceFile) Length() int { - return len(f.files) -} - -func (f *SliceFile) Size() (int64, error) { - var size int64 - - for _, file := range f.files { - sizeFile, ok := file.(SizeFile) - if !ok { - return 0, errors.New("Could not get size of child file") - } - - s, err := sizeFile.Size() - if err != nil { - return 0, err - } - size += s - } - - return size, nil -} diff --git a/commands/http/client.go b/commands/http/client.go index cb32c543a..704a54dd8 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -1,6 +1,7 @@ package http import ( + "context" "encoding/json" "errors" "fmt" @@ -15,7 +16,7 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" config "github.com/ipfs/go-ipfs/repo/config" - context "context" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) const ( @@ -54,16 +55,16 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { } // save user-provided encoding - previousUserProvidedEncoding, found, err := req.Option(cmds.EncShort).String() + previousUserProvidedEncoding, found, err := req.Option(cmdkit.EncShort).String() if err != nil { return nil, err } // override with json to send to server - req.SetOption(cmds.EncShort, cmds.JSON) + req.SetOption(cmdkit.EncShort, cmds.JSON) // stream channel output - req.SetOption(cmds.ChanOpt, "true") + req.SetOption(cmdkit.ChanOpt, "true") query, err := getQuery(req) if err != nil { @@ -112,7 +113,7 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { // reset to user provided encoding after sending request // NB: if user has provided an encoding but it is the empty string, // still leave it as JSON. - req.SetOption(cmds.EncShort, previousUserProvidedEncoding) + req.SetOption(cmdkit.EncShort, previousUserProvidedEncoding) } return res, nil @@ -136,7 +137,7 @@ func getQuery(req cmds.Request) (string, error) { for _, arg := range args { argDef := argDefs[argDefIndex] // skip ArgFiles - for argDef.Type == cmds.ArgFile { + for argDef.Type == cmdkit.ArgFile { argDefIndex++ argDef = argDefs[argDefIndex] } @@ -190,13 +191,12 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error // If we ran into an error if httpRes.StatusCode >= http.StatusBadRequest { - e := cmds.Error{} + var e *cmdkit.Error switch { case httpRes.StatusCode == http.StatusNotFound: // handle 404s - e.Message = "Command not found." - e.Code = cmds.ErrClient + e = &cmdkit.Error{Message: "Command not found.", Code: cmdkit.ErrClient} case contentType == plainText: // handle non-marshalled errors @@ -204,15 +204,16 @@ func getResponse(httpRes *http.Response, req cmds.Request) (cmds.Response, error if err != nil { return nil, err } - e.Message = string(mes) - e.Code = cmds.ErrNormal + e = &cmdkit.Error{Message: string(mes), Code: cmdkit.ErrNormal} default: // handle marshalled errors - err = dec.Decode(&e) + var rxErr cmdkit.Error + err = dec.Decode(&rxErr) if err != nil { return nil, err } + e = &rxErr } res.SetError(e, e.Code) @@ -245,7 +246,7 @@ func readStreamedJson(req cmds.Request, rr io.Reader, out chan<- interface{}, re if err != nil { if err != io.EOF { log.Error(err) - resp.SetError(err, cmds.ErrNormal) + resp.SetError(err, cmdkit.ErrNormal) } return } diff --git a/commands/http/handler.go b/commands/http/handler.go index ec40d1367..15cfd97ed 100644 --- a/commands/http/handler.go +++ b/commands/http/handler.go @@ -16,6 +16,7 @@ import ( "github.com/ipfs/go-ipfs/repo/config" cors "gx/ipfs/QmPG2kW5t27LuHgHnvhUwbHCNHAt2eUcb4gPHqofrESUdB/cors" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ) @@ -167,8 +168,8 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - rlog := i.ctx.ReqLog.Add(req) - defer rlog.Finish() + reqLogEnt := i.ctx.ReqLog.Add(req) + defer i.ctx.ReqLog.Finish(reqLogEnt) //ps: take note of the name clash - commands.Context != context.Context req.SetInvocContext(i.ctx) @@ -195,7 +196,7 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func guessMimeType(res cmds.Response) (string, error) { // Try to guess mimeType from the encoding option - enc, found, err := res.Request().Option(cmds.EncShort).String() + enc, found, err := res.Request().Option(cmdkit.EncShort).String() if err != nil { return "", err } @@ -224,7 +225,7 @@ func sendResponse(w http.ResponseWriter, r *http.Request, res cmds.Response, req status := http.StatusOK // if response contains an error, write an HTTP error status code if e := res.Error(); e != nil { - if e.Code == cmds.ErrClient { + if e.Code == cmdkit.ErrClient { status = http.StatusBadRequest } else { status = http.StatusInternalServerError diff --git a/commands/http/multifilereader.go b/commands/http/multifilereader.go index b09fe98c5..6f47c8106 100644 --- a/commands/http/multifilereader.go +++ b/commands/http/multifilereader.go @@ -9,7 +9,7 @@ import ( "net/url" "sync" - files "github.com/ipfs/go-ipfs/commands/files" + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" ) // MultiFileReader reads from a `commands.File` (which can be a directory of files diff --git a/commands/http/multifilereader_test.go b/commands/http/multifilereader_test.go index f7b87dfe8..92fcfd5c0 100644 --- a/commands/http/multifilereader_test.go +++ b/commands/http/multifilereader_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - files "github.com/ipfs/go-ipfs/commands/files" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" ) func TestOutput(t *testing.T) { diff --git a/commands/http/parse.go b/commands/http/parse.go index f87c55579..2c6bbbfd7 100644 --- a/commands/http/parse.go +++ b/commands/http/parse.go @@ -8,8 +8,10 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" - files "github.com/ipfs/go-ipfs/commands/files" path "github.com/ipfs/go-ipfs/path" + + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" ) // Parse parses the data in a http.Request and returns a command Request object @@ -31,7 +33,6 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) { if err != nil { // 404 if there is no command at that path return nil, ErrNotFound - } if sub := cmd.Subcommand(pth[len(pth)-1]); sub == nil { @@ -74,7 +75,7 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) { numRequired-- } - if argDef.Type == cmds.ArgString { + if argDef.Type == cmdkit.ArgString { if argDef.Variadic { for _, s := range stringArgs { args[valIndex] = s @@ -90,7 +91,7 @@ func Parse(r *http.Request, root *cmds.Command) (cmds.Request, error) { } else { break } - } else if argDef.Type == cmds.ArgFile && argDef.Required && len(requiredFile) == 0 { + } else if argDef.Type == cmdkit.ArgFile && argDef.Required && len(requiredFile) == 0 { requiredFile = argDef.Name } } @@ -149,10 +150,10 @@ func parseOptions(r *http.Request) (map[string]interface{}, []string) { } // default to setting encoding to JSON - _, short := opts[cmds.EncShort] - _, long := opts[cmds.EncLong] + _, short := opts[cmdkit.EncShort] + _, long := opts[cmdkit.EncLong] if !short && !long { - opts[cmds.EncShort] = cmds.JSON + opts[cmdkit.EncShort] = cmds.JSON } return opts, args diff --git a/commands/option.go b/commands/option.go deleted file mode 100644 index 1cf21ecf7..000000000 --- a/commands/option.go +++ /dev/null @@ -1,209 +0,0 @@ -package commands - -import ( - "fmt" - "reflect" - "strings" - - "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" -) - -// Types of Command options -const ( - Invalid = reflect.Invalid - Bool = reflect.Bool - Int = reflect.Int - Uint = reflect.Uint - Float = reflect.Float64 - String = reflect.String -) - -// Option is used to specify a field that will be provided by a consumer -type Option interface { - Names() []string // a list of unique names matched with user-provided flags - Type() reflect.Kind // value must be this type - Description() string // a short string that describes this option - Default(interface{}) Option // sets the default value of the option - DefaultVal() interface{} -} - -type option struct { - names []string - kind reflect.Kind - description string - defaultVal interface{} -} - -func (o *option) Names() []string { - return o.names -} - -func (o *option) Type() reflect.Kind { - return o.kind -} - -func (o *option) Description() string { - if len(o.description) == 0 { - return "" - } - if !strings.HasSuffix(o.description, ".") { - o.description += "." - } - if o.defaultVal != nil { - if strings.Contains(o.description, "<>") { - return strings.Replace(o.description, "<>", - fmt.Sprintf("Default: %v.", o.defaultVal), -1) - } else { - return fmt.Sprintf("%s Default: %v.", o.description, o.defaultVal) - } - } - return o.description -} - -// constructor helper functions -func NewOption(kind reflect.Kind, names ...string) Option { - if len(names) < 2 { - // FIXME(btc) don't panic (fix_before_merge) - panic("Options require at least two string values (name and description)") - } - - desc := names[len(names)-1] - names = names[:len(names)-1] - - return &option{ - names: names, - kind: kind, - description: desc, - } -} - -func (o *option) Default(v interface{}) Option { - o.defaultVal = v - return o -} - -func (o *option) DefaultVal() interface{} { - return o.defaultVal -} - -// TODO handle description separately. this will take care of the panic case in -// NewOption - -// For all func {Type}Option(...string) functions, the last variadic argument -// is treated as the description field. - -func BoolOption(names ...string) Option { - return NewOption(Bool, names...) -} -func IntOption(names ...string) Option { - return NewOption(Int, names...) -} -func UintOption(names ...string) Option { - return NewOption(Uint, names...) -} -func FloatOption(names ...string) Option { - return NewOption(Float, names...) -} -func StringOption(names ...string) Option { - return NewOption(String, names...) -} - -type OptionValue struct { - value interface{} - found bool - def Option -} - -// Found returns true if the option value was provided by the user (not a default value) -func (ov OptionValue) Found() bool { - return ov.found -} - -// Definition returns the option definition for the provided value -func (ov OptionValue) Definition() Option { - return ov.def -} - -// value accessor methods, gets the value as a certain type -func (ov OptionValue) Bool() (value bool, found bool, err error) { - if !ov.found && ov.value == nil { - return false, false, nil - } - val, ok := ov.value.(bool) - if !ok { - err = util.ErrCast() - } - return val, ov.found, err -} - -func (ov OptionValue) Int() (value int, found bool, err error) { - if !ov.found && ov.value == nil { - return 0, false, nil - } - val, ok := ov.value.(int) - if !ok { - err = util.ErrCast() - } - return val, ov.found, err -} - -func (ov OptionValue) Uint() (value uint, found bool, err error) { - if !ov.found && ov.value == nil { - return 0, false, nil - } - val, ok := ov.value.(uint) - if !ok { - err = util.ErrCast() - } - return val, ov.found, err -} - -func (ov OptionValue) Float() (value float64, found bool, err error) { - if !ov.found && ov.value == nil { - return 0, false, nil - } - val, ok := ov.value.(float64) - if !ok { - err = util.ErrCast() - } - return val, ov.found, err -} - -func (ov OptionValue) String() (value string, found bool, err error) { - if !ov.found && ov.value == nil { - return "", false, nil - } - val, ok := ov.value.(string) - if !ok { - err = util.ErrCast() - } - return val, ov.found, err -} - -// Flag names -const ( - EncShort = "enc" - EncLong = "encoding" - RecShort = "r" - RecLong = "recursive" - ChanOpt = "stream-channels" - TimeoutOpt = "timeout" -) - -// options that are used by this package -var OptionEncodingType = StringOption(EncLong, EncShort, "The encoding type the output should be encoded with (json, xml, or text)") -var OptionRecursivePath = BoolOption(RecLong, RecShort, "Add directory paths recursively").Default(false) -var OptionStreamChannels = BoolOption(ChanOpt, "Stream channel output") -var OptionTimeout = StringOption(TimeoutOpt, "set a global timeout on the command") - -// global options, added to every command -var globalOptions = []Option{ - OptionEncodingType, - OptionStreamChannels, - OptionTimeout, -} - -// the above array of Options, wrapped in a Command -var globalCommand = &Command{ - Options: globalOptions, -} diff --git a/commands/option_test.go b/commands/option_test.go deleted file mode 100644 index 99005cf4b..000000000 --- a/commands/option_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package commands - -import ( - "strings" - "testing" -) - -func TestOptionValueExtractBoolNotFound(t *testing.T) { - t.Log("ensure that no error is returned when value is not found") - optval := &OptionValue{found: false} - _, _, err := optval.Bool() - if err != nil { - t.Fatal("Found was false. Err should have been nil") - } -} - -func TestOptionValueExtractWrongType(t *testing.T) { - - t.Log("ensure that error is returned when value if of wrong type") - - optval := &OptionValue{value: "wrong type: a string", found: true} - _, _, err := optval.Bool() - if err == nil { - t.Fatal("No error returned. Failure.") - } - - optval = &OptionValue{value: "wrong type: a string", found: true} - _, _, err = optval.Int() - if err == nil { - t.Fatal("No error returned. Failure.") - } -} - -func TestLackOfDescriptionOfOptionDoesNotPanic(t *testing.T) { - opt := BoolOption("a", "") - opt.Description() -} - -func TestDotIsAddedInDescripton(t *testing.T) { - opt := BoolOption("a", "desc without dot") - dest := opt.Description() - if !strings.HasSuffix(dest, ".") { - t.Fatal("dot should have been added at the end of description") - } -} diff --git a/commands/reqlog.go b/commands/reqlog.go index b1884fae3..f9191d5dd 100644 --- a/commands/reqlog.go +++ b/commands/reqlog.go @@ -6,6 +6,7 @@ import ( "time" ) +// ReqLogEntry is an entry in the request log type ReqLogEntry struct { StartTime time.Time EndTime time.Time @@ -15,31 +16,17 @@ type ReqLogEntry struct { Args []string ID int - req Request log *ReqLog } -func (r *ReqLogEntry) Finish() { - log := r.log - log.lock.Lock() - defer log.lock.Unlock() - - r.Active = false - r.EndTime = time.Now() - r.log.maybeCleanup() - - // remove references to save memory - r.req = nil - r.log = nil - -} - +// Copy returns a copy of the ReqLogEntry func (r *ReqLogEntry) Copy() *ReqLogEntry { out := *r out.log = nil return &out } +// ReqLog is a log of requests type ReqLog struct { Requests []*ReqLogEntry nextID int @@ -47,10 +34,8 @@ type ReqLog struct { keep time.Duration } +// Add creates a ReqLogEntry from a request and adds it to the log func (rl *ReqLog) Add(req Request) *ReqLogEntry { - rl.lock.Lock() - defer rl.lock.Unlock() - rle := &ReqLogEntry{ StartTime: time.Now(), Active: true, @@ -58,18 +43,33 @@ func (rl *ReqLog) Add(req Request) *ReqLogEntry { Options: req.Options(), Args: req.StringArguments(), ID: rl.nextID, - req: req, log: rl, } - rl.nextID++ - rl.Requests = append(rl.Requests, rle) + rl.AddEntry(rle) return rle } +// AddEntry adds an entry to the log +func (rl *ReqLog) AddEntry(rle *ReqLogEntry) { + rl.lock.Lock() + defer rl.lock.Unlock() + + rl.nextID++ + rl.Requests = append(rl.Requests, rle) + + if rle == nil || !rle.Active { + rl.maybeCleanup() + } + + return +} + +// ClearInactive removes stale entries func (rl *ReqLog) ClearInactive() { rl.lock.Lock() defer rl.lock.Unlock() + k := rl.keep rl.keep = 0 rl.cleanup() @@ -97,6 +97,7 @@ func (rl *ReqLog) cleanup() { rl.Requests = rl.Requests[:i] } +// SetKeepTime sets a duration after which an entry will be considered inactive func (rl *ReqLog) SetKeepTime(t time.Duration) { rl.lock.Lock() defer rl.lock.Unlock() @@ -115,3 +116,14 @@ func (rl *ReqLog) Report() []*ReqLogEntry { return out } + +// Finish marks an entry in the log as finished +func (rl *ReqLog) Finish(rle *ReqLogEntry) { + rl.lock.Lock() + defer rl.lock.Unlock() + + rle.Active = false + rle.EndTime = time.Now() + + rl.maybeCleanup() +} diff --git a/commands/request.go b/commands/request.go index 33ac82937..983eeecf8 100644 --- a/commands/request.go +++ b/commands/request.go @@ -11,13 +11,13 @@ import ( "strconv" "time" - "github.com/ipfs/go-ipfs/commands/files" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/repo/config" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" -) -type OptMap map[string]interface{} + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" +) type Context struct { Online bool @@ -66,10 +66,10 @@ func (c *Context) NodeWithoutConstructing() *core.IpfsNode { // Request represents a call to a command from a consumer type Request interface { Path() []string - Option(name string) *OptionValue - Options() OptMap + Option(name string) *cmdkit.OptionValue + Options() cmdkit.OptMap SetOption(name string, val interface{}) - SetOptions(opts OptMap) error + SetOptions(opts cmdkit.OptMap) error Arguments() []string StringArguments() []string SetArguments([]string) @@ -89,13 +89,13 @@ type Request interface { type request struct { path []string - options OptMap + options cmdkit.OptMap arguments []string files files.File cmd *Command ctx Context rctx context.Context - optionDefs map[string]Option + optionDefs map[string]cmdkit.Option values map[string]interface{} stdin io.Reader } @@ -106,7 +106,7 @@ func (r *request) Path() []string { } // Option returns the value of the option for given name. -func (r *request) Option(name string) *OptionValue { +func (r *request) Option(name string) *cmdkit.OptionValue { // find the option with the specified name option, found := r.optionDefs[name] if !found { @@ -117,16 +117,16 @@ func (r *request) Option(name string) *OptionValue { for _, n := range option.Names() { val, found := r.options[n] if found { - return &OptionValue{val, found, option} + return &cmdkit.OptionValue{val, found, option} } } - return &OptionValue{option.DefaultVal(), false, option} + return &cmdkit.OptionValue{option.DefaultVal(), false, option} } // Options returns a copy of the option map -func (r *request) Options() OptMap { - output := make(OptMap) +func (r *request) Options() cmdkit.OptMap { + output := make(cmdkit.OptMap) for k, v := range r.options { output[k] = v } @@ -164,7 +164,7 @@ func (r *request) SetOption(name string, val interface{}) { } // SetOptions sets the option values, unsetting any values that were previously set -func (r *request) SetOptions(opts OptMap) error { +func (r *request) SetOptions(opts cmdkit.OptMap) error { r.options = opts return r.ConvertOptions() } @@ -212,7 +212,7 @@ func (r *request) haveVarArgsFromStdin() bool { } last := r.cmd.Arguments[len(r.cmd.Arguments)-1] - return last.SupportsStdin && last.Type == ArgString && (last.Required || last.Variadic) && + return last.SupportsStdin && last.Type == cmdkit.ArgString && (last.Required || last.Variadic) && len(r.arguments) < len(r.cmd.Arguments) } @@ -293,27 +293,27 @@ func (r *request) Command() *Command { type converter func(string) (interface{}, error) var converters = map[reflect.Kind]converter{ - Bool: func(v string) (interface{}, error) { + cmdkit.Bool: func(v string) (interface{}, error) { if v == "" { return true, nil } return strconv.ParseBool(v) }, - Int: func(v string) (interface{}, error) { + cmdkit.Int: func(v string) (interface{}, error) { val, err := strconv.ParseInt(v, 0, 32) if err != nil { return nil, err } return int(val), err }, - Uint: func(v string) (interface{}, error) { + cmdkit.Uint: func(v string) (interface{}, error) { val, err := strconv.ParseUint(v, 0, 32) if err != nil { return nil, err } return int(val), err }, - Float: func(v string) (interface{}, error) { + cmdkit.Float: func(v string) (interface{}, error) { return strconv.ParseFloat(v, 64) }, } @@ -335,7 +335,7 @@ func (r *request) ConvertOptions() error { kind := reflect.TypeOf(v).Kind() if kind != opt.Type() { - if kind == String { + if kind == cmdkit.String { convert := converters[opt.Type()] str, ok := v.(string) if !ok { @@ -378,12 +378,12 @@ func NewEmptyRequest() (Request, error) { // NewRequest returns a request initialized with given arguments // An non-nil error will be returned if the provided option values are invalid -func NewRequest(path []string, opts OptMap, args []string, file files.File, cmd *Command, optDefs map[string]Option) (Request, error) { +func NewRequest(path []string, opts cmdkit.OptMap, args []string, file files.File, cmd *Command, optDefs map[string]cmdkit.Option) (Request, error) { if opts == nil { - opts = make(OptMap) + opts = make(cmdkit.OptMap) } if optDefs == nil { - optDefs = make(map[string]Option) + optDefs = make(map[string]cmdkit.Option) } ctx := Context{} diff --git a/commands/response.go b/commands/response.go index 2c5b24210..9c75ba74d 100644 --- a/commands/response.go +++ b/commands/response.go @@ -8,30 +8,13 @@ import ( "io" "os" "strings" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) // ErrorType signfies a category of errors type ErrorType uint -// ErrorTypes convey what category of error ocurred -const ( - ErrNormal ErrorType = iota // general errors - ErrClient // error was caused by the client, (e.g. invalid CLI usage) - ErrImplementation // programmer error in the server - ErrNotFound // == HTTP 404 Not Found - // TODO: add more types of errors for better error-specific handling -) - -// Error is a struct for marshalling errors -type Error struct { - Message string - Code ErrorType -} - -func (e Error) Error() string { - return e.Message -} - // EncodingType defines a supported encoding type EncodingType string @@ -94,8 +77,8 @@ type Response interface { Request() Request // Set/Return the response Error - SetError(err error, code ErrorType) - Error() *Error + SetError(err error, code cmdkit.ErrorType) + Error() *cmdkit.Error // Sets/Returns the response value SetOutput(interface{}) @@ -123,7 +106,7 @@ type Response interface { type response struct { req Request - err *Error + err *cmdkit.Error value interface{} out io.Reader length uint64 @@ -152,12 +135,12 @@ func (r *response) SetLength(l uint64) { r.length = l } -func (r *response) Error() *Error { +func (r *response) Error() *cmdkit.Error { return r.err } -func (r *response) SetError(err error, code ErrorType) { - r.err = &Error{Message: err.Error(), Code: code} +func (r *response) SetError(err error, code cmdkit.ErrorType) { + r.err = &cmdkit.Error{Message: err.Error(), Code: code} } func (r *response) Marshal() (io.Reader, error) { @@ -165,7 +148,7 @@ func (r *response) Marshal() (io.Reader, error) { return bytes.NewReader([]byte{}), nil } - enc, found, err := r.req.Option(EncShort).String() + enc, found, err := r.req.Option(cmdkit.EncShort).String() if err != nil { return nil, err } diff --git a/commands/response_test.go b/commands/response_test.go index 4fe5d3b3b..94403b0b4 100644 --- a/commands/response_test.go +++ b/commands/response_test.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" "testing" + + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type TestOutput struct { @@ -26,7 +28,7 @@ func TestMarshalling(t *testing.T) { t.Error("Should have failed (no encoding type specified in request)") } - req.SetOption(EncShort, JSON) + req.SetOption(cmdkit.EncShort, JSON) reader, err := res.Marshal() if err != nil { @@ -39,7 +41,7 @@ func TestMarshalling(t *testing.T) { t.Error("Incorrect JSON output") } - res.SetError(fmt.Errorf("Oops!"), ErrClient) + res.SetError(fmt.Errorf("Oops!"), cmdkit.ErrClient) reader, err = res.Marshal() if err != nil { t.Error("Should have passed") @@ -48,13 +50,13 @@ func TestMarshalling(t *testing.T) { buf.ReadFrom(reader) output = buf.String() fmt.Println(removeWhitespace(output)) - if removeWhitespace(output) != "{\"Message\":\"Oops!\",\"Code\":1}" { + if removeWhitespace(output) != `{"Message":"Oops!","Code":1,"Type":"error"}` { t.Error("Incorrect JSON output") } } func TestErrTypeOrder(t *testing.T) { - if ErrNormal != 0 || ErrClient != 1 || ErrImplementation != 2 || ErrNotFound != 3 { + if cmdkit.ErrNormal != 0 || cmdkit.ErrClient != 1 || cmdkit.ErrImplementation != 2 || cmdkit.ErrNotFound != 3 { t.Fatal("ErrType order is wrong") } } diff --git a/core/bootstrap.go b/core/bootstrap.go index c86191c50..48907867e 100644 --- a/core/bootstrap.go +++ b/core/bootstrap.go @@ -1,6 +1,7 @@ package core import ( + "context" "errors" "fmt" "io" @@ -12,7 +13,6 @@ import ( math2 "github.com/ipfs/go-ipfs/thirdparty/math2" lgbl "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables" - context "context" inet "gx/ipfs/QmNa31VPzC561NWwRsJLE7nGYZYuuD2QfpK2b1q9BK54J1/go-libp2p-net" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" diff --git a/core/commands/active.go b/core/commands/active.go index 7a3163a75..95ff428c1 100644 --- a/core/commands/active.go +++ b/core/commands/active.go @@ -9,10 +9,13 @@ import ( "time" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var ActiveReqsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List commands run on this IPFS node.", ShortDescription: ` Lists running and recently run commands. @@ -21,8 +24,8 @@ Lists running and recently run commands. Run: func(req cmds.Request, res cmds.Response) { res.SetOutput(req.InvocContext().ReqLog.Report()) }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), }, Subcommands: map[string]*cmds.Command{ "clear": clearInactiveCmd, @@ -30,10 +33,14 @@ Lists running and recently run commands. }, Marshalers: map[cmds.EncodingType]cmds.Marshaler{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - out, ok := res.Output().(*[]*cmds.ReqLogEntry) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*[]*cmds.ReqLogEntry) if !ok { - log.Errorf("%#v", res.Output()) - return nil, cmds.ErrIncorrectType + return nil, e.TypeErr(out, v) } buf := new(bytes.Buffer) @@ -57,7 +64,7 @@ Lists running and recently run commands. if verbose { fmt.Fprintf(w, "%v\t[", req.Args) var keys []string - for k, _ := range req.Options { + for k := range req.Options { keys = append(keys, k) } sort.Strings(keys) @@ -86,7 +93,7 @@ Lists running and recently run commands. } var clearInactiveCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Clear inactive requests from the log.", }, Run: func(req cmds.Request, res cmds.Response) { @@ -95,16 +102,16 @@ var clearInactiveCmd = &cmds.Command{ } var setRequestClearCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Set how long to keep inactive requests in the log.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("time", true, false, "Time to keep inactive requests in log."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("time", true, false, "Time to keep inactive requests in log."), }, Run: func(req cmds.Request, res cmds.Response) { tval, err := time.ParseDuration(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } diff --git a/core/commands/add.go b/core/commands/add.go index 93c7b4cc9..5ac2de87f 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -4,12 +4,11 @@ import ( "errors" "fmt" "io" + "os" "strings" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" blockservice "github.com/ipfs/go-ipfs/blockservice" - cmds "github.com/ipfs/go-ipfs/commands" - files "github.com/ipfs/go-ipfs/commands/files" core "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/coreunix" offline "github.com/ipfs/go-ipfs/exchange/offline" @@ -18,12 +17,14 @@ import ( mfs "github.com/ipfs/go-ipfs/mfs" ft "github.com/ipfs/go-ipfs/unixfs" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash" "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" ) -// Error indicating the max depth has been exceded. +// ErrDepthLimitExceeded indicates that the max depth has been exceded. var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded") const ( @@ -47,7 +48,7 @@ const ( const adderOutChanSize = 8 var AddCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Add a file or directory to ipfs.", ShortDescription: ` Adds contents of to ipfs. Use -r to add directories (recursively). @@ -98,26 +99,26 @@ You can now check what blocks have been created by: `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(), }, - Options: []cmds.Option{ - cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive) - cmds.BoolOption(quietOptionName, "q", "Write minimal output."), - cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."), - cmds.BoolOption(silentOptionName, "Write no output."), - cmds.BoolOption(progressOptionName, "p", "Stream progress data."), - cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."), - cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."), - cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."), - cmds.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."), - cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]").Default("size-262144"), - cmds.BoolOption(pinOptionName, "Pin this object when adding.").Default(true), - cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"), - cmds.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"), - cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"), - cmds.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0), - cmds.StringOption(hashOptionName, "Hash function to use. Will set Cid version to 1 if used. (experimental)").Default("sha2-256"), + Options: []cmdkit.Option{ + cmdkit.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive) + cmdkit.BoolOption(quietOptionName, "q", "Write minimal output."), + cmdkit.BoolOption(quieterOptionName, "Q", "Write only final hash."), + cmdkit.BoolOption(silentOptionName, "Write no output."), + cmdkit.BoolOption(progressOptionName, "p", "Stream progress data."), + cmdkit.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."), + cmdkit.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."), + cmdkit.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."), + cmdkit.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."), + cmdkit.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]").Default("size-262144"), + cmdkit.BoolOption(pinOptionName, "Pin this object when adding.").Default(true), + cmdkit.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"), + cmdkit.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"), + cmdkit.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"), + cmdkit.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0), + cmdkit.StringOption(hashOptionName, "Hash function to use. Will set Cid version to 1 if used. (experimental)").Default("sha2-256"), }, PreRun: func(req cmds.Request) error { quiet, _, _ := req.Option(quietOptionName).Bool() @@ -154,29 +155,28 @@ You can now check what blocks have been created by: return } - log.Debugf("Total size of file being added: %v\n", size) sizeCh <- size }() return nil }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } cfg, err := n.Repo.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // check if repo will exceed storage limit if added // TODO: this doesn't handle the case if the hashed file is already in blocks (deduplicated) // TODO: conditional GC is disabled due to it is somehow not possible to pass the size to the daemon //if err := corerepo.ConditionalGC(req.Context(), n, uint64(size)); err != nil { - // res.SetError(err, cmds.ErrNormal) + // res.SetError(err, cmdkit.ErrNormal) // return //} @@ -196,7 +196,7 @@ You can now check what blocks have been created by: if nocopy && !cfg.Experimental.FilestoreEnabled { res.SetError(errors.New("filestore is not enabled, see https://git.io/vy4XN"), - cmds.ErrClient) + cmdkit.ErrClient) return } @@ -205,7 +205,7 @@ You can now check what blocks have been created by: } if nocopy && !rawblks { - res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmds.ErrNormal) + res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmdkit.ErrNormal) return } @@ -219,13 +219,13 @@ You can now check what blocks have been created by: prefix, err := dag.PrefixForCidVersion(cidVer) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)] if !ok { - res.SetError(fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)), cmds.ErrNormal) + res.SetError(fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)), cmdkit.ErrNormal) return } @@ -239,7 +239,7 @@ You can now check what blocks have been created by: NilRepo: true, }) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } n = nilnode @@ -259,15 +259,14 @@ You can now check what blocks have been created by: bserv := blockservice.New(addblockstore, exch) dserv := dag.NewDAGService(bserv) + outChan := make(chan interface{}, adderOutChanSize) + fileAdder, err := coreunix.NewAdder(req.Context(), n.Pinning, n.Blockstore, dserv) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - outChan := make(chan interface{}, adderOutChanSize) - res.SetOutput((<-chan interface{})(outChan)) - fileAdder.Out = outChan fileAdder.Chunker = chunker fileAdder.Progress = progress @@ -284,7 +283,7 @@ You can now check what blocks have been created by: md := dagtest.Mock() mr, err := mfs.NewRoot(req.Context(), md, ft.EmptyDirNode(), nil) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -321,112 +320,161 @@ You can now check what blocks have been created by: return fileAdder.PinRoot() } + errCh := make(chan error) go func() { + var err error + defer func() { errCh <- err }() defer close(outChan) - if err := addAllAndPin(req.Files()); err != nil { - res.SetError(err, cmds.ErrNormal) - return - } - + err = addAllAndPin(req.Files()) }() + + defer res.Close() + + err = res.Emit(outChan) + if err != nil { + log.Error(err) + return + } + err = <-errCh + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + } }, - PostRun: func(req cmds.Request, res cmds.Response) { - if res.Error() != nil { - return - } - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - res.SetError(u.ErrCast(), cmds.ErrNormal) - return - } - res.SetOutput(nil) + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{ + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter { + reNext, res := cmds.NewChanResponsePair(req) + outChan := make(chan interface{}) - quiet, _, _ := req.Option(quietOptionName).Bool() - quieter, _, _ := req.Option(quieterOptionName).Bool() - quiet = quiet || quieter + progressBar := func(wait chan struct{}) { + defer close(wait) - progress, _, _ := req.Option(progressOptionName).Bool() + quiet, _, _ := req.Option(quietOptionName).Bool() + quieter, _, _ := req.Option(quieterOptionName).Bool() + quiet = quiet || quieter - var bar *pb.ProgressBar - if progress { - bar = pb.New64(0).SetUnits(pb.U_BYTES) - bar.ManualUpdate = true - bar.ShowTimeLeft = false - bar.ShowPercent = false - bar.Output = res.Stderr() - bar.Start() - } - - var sizeChan chan int64 - s, found := req.Values()["size"] - if found { - sizeChan = s.(chan int64) - } - - lastFile := "" - lastHash := "" - var totalProgress, prevFiles, lastBytes int64 - - LOOP: - for { - select { - case out, ok := <-outChan: - if !ok { - if quieter { - fmt.Fprintln(res.Stdout(), lastHash) - } - break LOOP - } - output := out.(*coreunix.AddedObject) - if len(output.Hash) > 0 { - lastHash = output.Hash - if quieter { - continue - } - - if progress { - // clear progress bar line before we print "added x" output - fmt.Fprintf(res.Stderr(), "\033[2K\r") - } - if quiet { - fmt.Fprintf(res.Stdout(), "%s\n", output.Hash) - } else { - fmt.Fprintf(res.Stdout(), "added %s %s\n", output.Hash, output.Name) - } - } else { - log.Debugf("add progress: %v %v\n", output.Name, output.Bytes) - - if !progress { - continue - } - - if len(lastFile) == 0 { - lastFile = output.Name - } - if output.Name != lastFile || output.Bytes < lastBytes { - prevFiles += lastBytes - lastFile = output.Name - } - lastBytes = output.Bytes - delta := prevFiles + lastBytes - totalProgress - totalProgress = bar.Add64(delta) - } + progress, _, _ := req.Option(progressOptionName).Bool() + var bar *pb.ProgressBar if progress { - bar.Update() + bar = pb.New64(0).SetUnits(pb.U_BYTES) + bar.ManualUpdate = true + bar.ShowTimeLeft = false + bar.ShowPercent = false + bar.Output = os.Stderr + bar.Start() } - case size := <-sizeChan: - if progress { - bar.Total = size - bar.ShowPercent = true - bar.ShowBar = true - bar.ShowTimeLeft = true + + var sizeChan chan int64 + s, found := req.Values()["size"] + if found { + sizeChan = s.(chan int64) + } + + lastFile := "" + lastHash := "" + var totalProgress, prevFiles, lastBytes int64 + + LOOP: + for { + select { + case out, ok := <-outChan: + if !ok { + if quieter { + fmt.Fprintln(os.Stdout, lastHash) + } + + break LOOP + } + output := out.(*coreunix.AddedObject) + if len(output.Hash) > 0 { + lastHash = output.Hash + if quieter { + continue + } + + if progress { + // clear progress bar line before we print "added x" output + fmt.Fprintf(os.Stderr, "\033[2K\r") + } + if quiet { + fmt.Fprintf(os.Stdout, "%s\n", output.Hash) + } else { + fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name) + } + + } else { + if !progress { + continue + } + + if len(lastFile) == 0 { + lastFile = output.Name + } + if output.Name != lastFile || output.Bytes < lastBytes { + prevFiles += lastBytes + lastFile = output.Name + } + lastBytes = output.Bytes + delta := prevFiles + lastBytes - totalProgress + totalProgress = bar.Add64(delta) + } + + if progress { + bar.Update() + } + case size := <-sizeChan: + if progress { + bar.Total = size + bar.ShowPercent = true + bar.ShowBar = true + bar.ShowTimeLeft = true + } + case <-req.Context().Done(): + re.SetError(req.Context().Err(), cmdkit.ErrNormal) + return + } } - case <-req.Context().Done(): - res.SetError(req.Context().Err(), cmds.ErrNormal) - return } - } + + go func() { + // defer order important! First close outChan, then wait for output to finish, then close re + defer re.Close() + + if e := res.Error(); e != nil { + defer close(outChan) + re.SetError(e.Message, e.Code) + return + } + + wait := make(chan struct{}) + go progressBar(wait) + + defer func() { <-wait }() + defer close(outChan) + + for { + v, err := res.Next() + if err != nil { + // replace error by actual error - will be looked at by next if-statement + if err == cmds.ErrRcvdError { + err = res.Error() + } + + if e, ok := err.(*cmdkit.Error); ok { + re.Emit(e) + } else if err != io.EOF { + re.SetError(err, cmdkit.ErrNormal) + } + + return + } + + outChan <- v + } + }() + + return reNext + }, }, Type: coreunix.AddedObject{}, } diff --git a/core/commands/bitswap.go b/core/commands/bitswap.go index fae62c538..1faca19c3 100644 --- a/core/commands/bitswap.go +++ b/core/commands/bitswap.go @@ -5,52 +5,57 @@ import ( "fmt" "io" - cmds "github.com/ipfs/go-ipfs/commands" + oldcmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" bitswap "github.com/ipfs/go-ipfs/exchange/bitswap" decision "github.com/ipfs/go-ipfs/exchange/bitswap/decision" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ) var BitswapCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with the bitswap agent.", ShortDescription: ``, }, + Subcommands: map[string]*cmds.Command{ + "stat": bitswapStatCmd, + }, + OldSubcommands: map[string]*oldcmds.Command{ "wantlist": showWantlistCmd, - "stat": bitswapStatCmd, "unwant": unwantCmd, "ledger": ledgerCmd, "reprovide": reprovideCmd, }, } -var unwantCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var unwantCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Remove a given block from your wantlist.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, true, "Key(s) to remove from your wantlist.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, true, "Key(s) to remove from your wantlist.").EnableStdin(), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !nd.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } bs, ok := nd.Exchange.(*bitswap.Bitswap) if !ok { - res.SetError(u.ErrCast(), cmds.ErrNormal) + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal) return } @@ -58,7 +63,7 @@ var unwantCmd = &cmds.Command{ for _, arg := range req.Arguments() { c, err := cid.Decode(arg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -73,43 +78,43 @@ var unwantCmd = &cmds.Command{ }, } -var showWantlistCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var showWantlistCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Show blocks currently on the wantlist.", ShortDescription: ` Print out all blocks currently on the bitswap wantlist for the local peer.`, }, - Options: []cmds.Option{ - cmds.StringOption("peer", "p", "Specify which peer to show wantlist for. Default: self."), + Options: []cmdkit.Option{ + cmdkit.StringOption("peer", "p", "Specify which peer to show wantlist for. Default: self."), }, Type: KeyList{}, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !nd.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } bs, ok := nd.Exchange.(*bitswap.Bitswap) if !ok { - res.SetError(u.ErrCast(), cmds.ErrNormal) + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal) return } pstr, found, err := req.Option("peer").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if found { pid, err := peer.IDB58Decode(pstr) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if pid == nd.Identity { @@ -122,73 +127,74 @@ Print out all blocks currently on the bitswap wantlist for the local peer.`, res.SetOutput(&KeyList{bs.GetWantlist()}) } }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: KeyListTextMarshaler, + Marshalers: oldcmds.MarshalerMap{ + oldcmds.Text: KeyListTextMarshaler, }, } var bitswapStatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Show some diagnostic information on the bitswap agent.", ShortDescription: ``, }, Type: bitswap.Stat{}, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !nd.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } bs, ok := nd.Exchange.(*bitswap.Bitswap) if !ok { - res.SetError(u.ErrCast(), cmds.ErrNormal) + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal) return } st, err := bs.Stat() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(st) + res.Emit(st) }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - out, ok := res.Output().(*bitswap.Stat) + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + out, ok := v.(*bitswap.Stat) if !ok { - return nil, u.ErrCast() + return e.TypeErr(out, v) } - buf := new(bytes.Buffer) - fmt.Fprintln(buf, "bitswap status") - fmt.Fprintf(buf, "\tprovides buffer: %d / %d\n", out.ProvideBufLen, bitswap.HasBlockBufferSize) - fmt.Fprintf(buf, "\tblocks received: %d\n", out.BlocksReceived) - fmt.Fprintf(buf, "\tblocks sent: %d\n", out.BlocksSent) - fmt.Fprintf(buf, "\tdata received: %d\n", out.DataReceived) - fmt.Fprintf(buf, "\tdata sent: %d\n", out.DataSent) - fmt.Fprintf(buf, "\tdup blocks received: %d\n", out.DupBlksReceived) - fmt.Fprintf(buf, "\tdup data received: %s\n", humanize.Bytes(out.DupDataReceived)) - fmt.Fprintf(buf, "\twantlist [%d keys]\n", len(out.Wantlist)) + + fmt.Fprintln(w, "bitswap status") + fmt.Fprintf(w, "\tprovides buffer: %d / %d\n", out.ProvideBufLen, bitswap.HasBlockBufferSize) + fmt.Fprintf(w, "\tblocks received: %d\n", out.BlocksReceived) + fmt.Fprintf(w, "\tblocks sent: %d\n", out.BlocksSent) + fmt.Fprintf(w, "\tdata received: %d\n", out.DataReceived) + fmt.Fprintf(w, "\tdata sent: %d\n", out.DataSent) + fmt.Fprintf(w, "\tdup blocks received: %d\n", out.DupBlksReceived) + fmt.Fprintf(w, "\tdup data received: %s\n", humanize.Bytes(out.DupDataReceived)) + fmt.Fprintf(w, "\twantlist [%d keys]\n", len(out.Wantlist)) for _, k := range out.Wantlist { - fmt.Fprintf(buf, "\t\t%s\n", k.String()) + fmt.Fprintf(w, "\t\t%s\n", k.String()) } - fmt.Fprintf(buf, "\tpartners [%d]\n", len(out.Peers)) + fmt.Fprintf(w, "\tpartners [%d]\n", len(out.Peers)) for _, p := range out.Peers { - fmt.Fprintf(buf, "\t\t%s\n", p) + fmt.Fprintf(w, "\t\t%s\n", p) } - return buf, nil - }, + + return nil + }), }, } -var ledgerCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var ledgerCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Show the current ledger for a peer.", ShortDescription: ` The Bitswap decision engine tracks the number of bytes exchanged between IPFS @@ -196,41 +202,47 @@ nodes, and stores this information as a collection of ledgers. This command prints the ledger associated with a given peer. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."), }, Type: decision.Receipt{}, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !nd.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } bs, ok := nd.Exchange.(*bitswap.Bitswap) if !ok { - res.SetError(u.ErrCast(), cmds.ErrNormal) + res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal) return } partner, err := peer.IDB58Decode(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrClient) + res.SetError(err, cmdkit.ErrClient) return } res.SetOutput(bs.LedgerForPeer(partner)) }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - out, ok := res.Output().(*decision.Receipt) - if !ok { - return nil, u.ErrCast() + Marshalers: oldcmds.MarshalerMap{ + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err } + + out, ok := v.(*decision.Receipt) + if !ok { + return nil, e.TypeErr(out, v) + } + buf := new(bytes.Buffer) fmt.Fprintf(buf, "Ledger for %s\n"+ "Debt ratio:\t%f\n"+ @@ -244,29 +256,31 @@ prints the ledger associated with a given peer. }, } -var reprovideCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var reprovideCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Trigger reprovider.", ShortDescription: ` Trigger reprovider to announce our data to network. `, }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !nd.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } err = nd.Reprovider.Trigger(req.Context()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } + + res.SetOutput(nil) }, } diff --git a/core/commands/block.go b/core/commands/block.go index 9981ddfca..fdc1ac9c8 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -5,13 +5,14 @@ import ( "fmt" "io" "io/ioutil" - "strings" + "os" util "github.com/ipfs/go-ipfs/blocks/blockstore/util" - cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash" ) @@ -26,7 +27,7 @@ func (bs BlockStat) String() string { } var BlockCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with raw IPFS blocks.", ShortDescription: ` 'ipfs block' is a plumbing command used to manipulate raw IPFS blocks. @@ -44,7 +45,7 @@ multihash. } var blockStatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Print information of a raw IPFS block.", ShortDescription: ` 'ipfs block stat' is a plumbing command for retrieving information @@ -56,32 +57,39 @@ on raw IPFS blocks. It outputs the following to stdout: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { b, err := getBlockForKey(req, req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(&BlockStat{ + err = res.Emit(&BlockStat{ Key: b.Cid().String(), Size: len(b.RawData()), }) + if err != nil { + log.Error(err) + } }, Type: BlockStat{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - bs := res.Output().(*BlockStat) - return strings.NewReader(bs.String()), nil - }, + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + bs, ok := v.(*BlockStat) + if !ok { + return e.TypeErr(bs, v) + } + _, err := fmt.Fprintf(w, "%s", bs) + return err + }), }, } var blockGetCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Get a raw IPFS block.", ShortDescription: ` 'ipfs block get' is a plumbing command for retrieving raw IPFS blocks. @@ -89,22 +97,25 @@ It outputs to stdout, and is a base58 encoded multihash. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { b, err := getBlockForKey(req, req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(bytes.NewReader(b.RawData())) + err = res.Emit(bytes.NewReader(b.RawData())) + if err != nil { + log.Error(err) + } }, } var blockPutCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Store input as an IPFS block.", ShortDescription: ` 'ipfs block put' is a plumbing command for storing raw IPFS blocks. @@ -112,36 +123,36 @@ It reads from stdin, and is a base58 encoded multihash. `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("data", true, false, "The data to be stored as an IPFS block.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("data", true, false, "The data to be stored as an IPFS block.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.StringOption("format", "f", "cid format for blocks to be created with.").Default("v0"), - cmds.StringOption("mhtype", "multihash hash function").Default("sha2-256"), - cmds.IntOption("mhlen", "multihash hash length").Default(-1), + Options: []cmdkit.Option{ + cmdkit.StringOption("format", "f", "cid format for blocks to be created with.").Default("v0"), + cmdkit.StringOption("mhtype", "multihash hash function").Default("sha2-256"), + cmdkit.IntOption("mhlen", "multihash hash length").Default(-1), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } file, err := req.Files().NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } data, err := ioutil.ReadAll(file) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = file.Close() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -151,7 +162,7 @@ It reads from stdin, and is a base58 encoded multihash. format, _, _ := req.Option("format").String() formatval, ok := cid.Codecs[format] if !ok { - res.SetError(fmt.Errorf("unrecognized format: %s", format), cmds.ErrNormal) + res.SetError(fmt.Errorf("unrecognized format: %s", format), cmdkit.ErrNormal) return } if format == "v0" { @@ -162,47 +173,54 @@ It reads from stdin, and is a base58 encoded multihash. mhtype, _, _ := req.Option("mhtype").String() mhtval, ok := mh.Names[mhtype] if !ok { - res.SetError(fmt.Errorf("unrecognized multihash function: %s", mhtype), cmds.ErrNormal) + err := fmt.Errorf("unrecognized multihash function: %s", mhtype) + res.SetError(err, cmdkit.ErrNormal) return } pref.MhType = mhtval mhlen, _, err := req.Option("mhlen").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pref.MhLength = mhlen bcid, err := pref.Sum(data) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } b, err := blocks.NewBlockWithCid(data, bcid) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - log.Debugf("BlockPut key: '%q'", b.Cid()) k, err := n.Blocks.AddBlock(b) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(&BlockStat{ + err = res.Emit(&BlockStat{ Key: k.String(), Size: len(data), }) + if err != nil { + log.Error(err) + } }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - bs := res.Output().(*BlockStat) - return strings.NewReader(bs.Key + "\n"), nil - }, + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + bs, ok := v.(*BlockStat) + if !ok { + return e.TypeErr(bs, v) + } + _, err := fmt.Fprintf(w, "%s\n", bs.Key) + return err + }), }, Type: BlockStat{}, } @@ -227,29 +245,28 @@ func getBlockForKey(req cmds.Request, skey string) (blocks.Block, error) { return nil, err } - log.Debugf("ipfs block: got block with key: %s", b.Cid()) return b, nil } var blockRmCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove IPFS block(s).", ShortDescription: ` 'ipfs block rm' is a plumbing command for removing raw ipfs blocks. It takes a list of base58 encoded multihashs to remove. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."), }, - Options: []cmds.Option{ - cmds.BoolOption("force", "f", "Ignore nonexistent blocks.").Default(false), - cmds.BoolOption("quiet", "q", "Write minimal output.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("force", "f", "Ignore nonexistent blocks.").Default(false), + cmdkit.BoolOption("quiet", "q", "Write minimal output.").Default(false), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } hashes := req.Arguments() @@ -259,7 +276,8 @@ It takes a list of base58 encoded multihashs to remove. for _, hash := range hashes { c, err := cid.Decode(hash) if err != nil { - res.SetError(fmt.Errorf("invalid content id: %s (%s)", hash, err), cmds.ErrNormal) + err = fmt.Errorf("invalid content id: %s (%s)", hash, err) + res.SetError(err, cmdkit.ErrNormal) return } @@ -269,21 +287,29 @@ It takes a list of base58 encoded multihashs to remove. Quiet: quiet, Force: force, }) + if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(ch) - }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - err := util.ProcRmOutput(outChan, res.Stdout(), res.Stderr()) - return nil, err + err = res.Emit(ch) + if err != nil { + log.Error(err) + } + }, + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{ + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter { + reNext, res := cmds.NewChanResponsePair(req) + + go func() { + defer re.Close() + + err := util.ProcRmOutput(res.Next, os.Stdout, os.Stderr) + cmds.HandleError(err, res, re) + }() + + return reNext }, }, Type: util.RemovedBlock{}, diff --git a/core/commands/bootstrap.go b/core/commands/bootstrap.go index bf95b1fe7..3f5edeba6 100644 --- a/core/commands/bootstrap.go +++ b/core/commands/bootstrap.go @@ -7,10 +7,12 @@ import ( "sort" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" repo "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/repo/fsrepo" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type BootstrapOutput struct { @@ -20,7 +22,7 @@ type BootstrapOutput struct { var peerOptionDesc = "A peer to add to the bootstrap list (in the format '/')" var BootstrapCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Show or edit the list of bootstrap peers.", ShortDescription: ` Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. @@ -39,19 +41,19 @@ Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. } var bootstrapAddCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Add peers to the bootstrap list.", ShortDescription: `Outputs a list of peers that were added (that weren't already in the bootstrap list). ` + bootstrapSecurityWarning, }, - Arguments: []cmds.Argument{ - cmds.StringArg("peer", false, true, peerOptionDesc).EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peer", false, true, peerOptionDesc).EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("default", "Add default bootstrap nodes. (Deprecated, use 'default' subcommand instead)"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("default", "Add default bootstrap nodes. (Deprecated, use 'default' subcommand instead)"), }, Subcommands: map[string]*cmds.Command{ "default": bootstrapAddDefaultCmd, @@ -60,7 +62,7 @@ in the bootstrap list). Run: func(req cmds.Request, res cmds.Response) { deflt, _, err := req.Option("default").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -69,7 +71,7 @@ in the bootstrap list). // parse separately for meaningful, correct error. defltPeers, err := config.DefaultBootstrapPeers() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -77,7 +79,7 @@ in the bootstrap list). } else { parsedPeers, err := config.ParseBootstrapPeers(req.Arguments()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -85,25 +87,25 @@ in the bootstrap list). } if len(inputPeers) == 0 { - res.SetError(errors.New("no bootstrap peers to add"), cmds.ErrClient) + res.SetError(errors.New("no bootstrap peers to add"), cmdkit.ErrClient) return } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } added, err := bootstrapAdd(r, cfg, inputPeers) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -112,13 +114,18 @@ in the bootstrap list). Type: BootstrapOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v, ok := res.Output().(*BootstrapOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*BootstrapOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(out, v) } buf := new(bytes.Buffer) - if err := bootstrapWritePeers(buf, "added ", v.Peers); err != nil { + if err := bootstrapWritePeers(buf, "added ", out.Peers); err != nil { return nil, err } @@ -128,7 +135,7 @@ in the bootstrap list). } var bootstrapAddDefaultCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Add default peers to the bootstrap list.", ShortDescription: `Outputs a list of peers that were added (that weren't already in the bootstrap list).`, @@ -136,26 +143,26 @@ in the bootstrap list).`, Run: func(req cmds.Request, res cmds.Response) { defltPeers, err := config.DefaultBootstrapPeers() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } added, err := bootstrapAdd(r, cfg, defltPeers) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -164,13 +171,18 @@ in the bootstrap list).`, Type: BootstrapOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v, ok := res.Output().(*BootstrapOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*BootstrapOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(out, v) } buf := new(bytes.Buffer) - if err := bootstrapWritePeers(buf, "added ", v.Peers); err != nil { + if err := bootstrapWritePeers(buf, "added ", out.Peers); err != nil { return nil, err } @@ -180,17 +192,17 @@ in the bootstrap list).`, } var bootstrapRemoveCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove peers from the bootstrap list.", ShortDescription: `Outputs the list of peers that were removed. ` + bootstrapSecurityWarning, }, - Arguments: []cmds.Argument{ - cmds.StringArg("peer", false, true, peerOptionDesc).EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peer", false, true, peerOptionDesc).EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("all", "Remove all bootstrap peers. (Deprecated, use 'all' subcommand)"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("all", "Remove all bootstrap peers. (Deprecated, use 'all' subcommand)"), }, Subcommands: map[string]*cmds.Command{ "all": bootstrapRemoveAllCmd, @@ -198,19 +210,19 @@ var bootstrapRemoveCmd = &cmds.Command{ Run: func(req cmds.Request, res cmds.Response) { all, _, err := req.Option("all").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -220,14 +232,14 @@ var bootstrapRemoveCmd = &cmds.Command{ } else { input, perr := config.ParseBootstrapPeers(req.Arguments()) if perr != nil { - res.SetError(perr, cmds.ErrNormal) + res.SetError(perr, cmdkit.ErrNormal) return } removed, err = bootstrapRemove(r, cfg, input) } if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -236,20 +248,25 @@ var bootstrapRemoveCmd = &cmds.Command{ Type: BootstrapOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v, ok := res.Output().(*BootstrapOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*BootstrapOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(out, v) } buf := new(bytes.Buffer) - err := bootstrapWritePeers(buf, "removed ", v.Peers) + err = bootstrapWritePeers(buf, "removed ", out.Peers) return buf, err }, }, } var bootstrapRemoveAllCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove all peers from the bootstrap list.", ShortDescription: `Outputs the list of peers that were removed.`, }, @@ -257,19 +274,19 @@ var bootstrapRemoveAllCmd = &cmds.Command{ Run: func(req cmds.Request, res cmds.Response) { r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } removed, err := bootstrapRemoveAll(r, cfg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -278,20 +295,25 @@ var bootstrapRemoveAllCmd = &cmds.Command{ Type: BootstrapOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v, ok := res.Output().(*BootstrapOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*BootstrapOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(out, v) } buf := new(bytes.Buffer) - err := bootstrapWritePeers(buf, "removed ", v.Peers) + err = bootstrapWritePeers(buf, "removed ", out.Peers) return buf, err }, }, } var bootstrapListCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Show peers in the bootstrap list.", ShortDescription: "Peers are output in the format '/'.", }, @@ -299,19 +321,19 @@ var bootstrapListCmd = &cmds.Command{ Run: func(req cmds.Request, res cmds.Response) { r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } peers, err := cfg.BootstrapPeers() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&BootstrapOutput{config.BootstrapPeerStrings(peers)}) @@ -323,13 +345,18 @@ var bootstrapListCmd = &cmds.Command{ } func bootstrapMarshaler(res cmds.Response) (io.Reader, error) { - v, ok := res.Output().(*BootstrapOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*BootstrapOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(out, v) } buf := new(bytes.Buffer) - err := bootstrapWritePeers(buf, "", v.Peers) + err = bootstrapWritePeers(buf, "", out.Peers) return buf, err } diff --git a/core/commands/cat.go b/core/commands/cat.go index 5f5ac57fb..80247629b 100644 --- a/core/commands/cat.go +++ b/core/commands/cat.go @@ -1,67 +1,105 @@ package commands import ( + "context" "io" + "os" - cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" - context "context" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB var CatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Show IPFS object data.", ShortDescription: "Displays the data contained by an IPFS or IPNS object(s) at the given path.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted.").EnableStdin(), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !node.OnlineMode() { if err := node.SetupOfflineRouting(); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } readers, length, err := cat(req.Context(), node, req.Arguments()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } /* if err := corerepo.ConditionalGC(req.Context(), node, length); err != nil { - res.SetError(err, cmds.ErrNormal) + re.SetError(err, cmdkit.ErrNormal) return } */ res.SetLength(length) - reader := io.MultiReader(readers...) - res.SetOutput(reader) - }, - PostRun: func(req cmds.Request, res cmds.Response) { - if res.Length() < progressBarMinSize { - return + + // Since the reader returns the error that a block is missing, and that error is + // returned from io.Copy inside Emit, we need to take Emit errors and send + // them to the client. Usually we don't do that because it means the connection + // is broken or we supplied an illegal argument etc. + err = res.Emit(reader) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) } + }, + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{ + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter { + reNext, res := cmds.NewChanResponsePair(req) - bar, reader := progressBarForReader(res.Stderr(), res.Output().(io.Reader), int64(res.Length())) - bar.Start() + go func() { + if res.Length() > 0 && res.Length() < progressBarMinSize { + if err := cmds.Copy(re, res); err != nil { + re.SetError(err, cmdkit.ErrNormal) + } - res.SetOutput(reader) + return + } + + // Copy closes by itself, so we must not do this before + defer re.Close() + for { + v, err := res.Next() + if !cmds.HandleError(err, res, re) { + break + } + + switch val := v.(type) { + case io.Reader: + bar, reader := progressBarForReader(os.Stderr, val, int64(res.Length())) + bar.Start() + + err = re.Emit(reader) + if err != nil { + log.Error(err) + } + default: + log.Warningf("cat postrun: received unexpected type %T", val) + } + } + }() + + return reNext + }, }, } diff --git a/core/commands/commands.go b/core/commands/commands.go index 0f37bb727..f91e263f3 100644 --- a/core/commands/commands.go +++ b/core/commands/commands.go @@ -6,18 +6,48 @@ package commands import ( - "bytes" + "fmt" "io" "sort" "strings" - cmds "github.com/ipfs/go-ipfs/commands" + oldcmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" + + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) +type commandEncoder struct { + w io.Writer +} + +func (e *commandEncoder) Encode(v interface{}) error { + var ( + cmd *Command + ok bool + ) + + if cmd, ok = v.(*Command); !ok { + return fmt.Errorf(`core/commands: uenxpected type %T, expected *"core/commands".Command`, v) + } + + for _, s := range cmdPathStrings(cmd, cmd.showOpts) { + _, err := e.w.Write([]byte(s + "\n")) + if err != nil { + return err + } + } + + return nil +} + type Command struct { Name string Subcommands []Command Options []Option + + showOpts bool } type Option struct { @@ -32,26 +62,24 @@ const ( // and returns a command that lists the subcommands in that root func CommandsCmd(root *cmds.Command) *cmds.Command { return &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List all available commands.", ShortDescription: `Lists all available commands (and subcommands) and exits.`, }, - Options: []cmds.Option{ - cmds.BoolOption(flagsOptionName, "f", "Show command flags").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption(flagsOptionName, "f", "Show command flags").Default(false), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { rootCmd := cmd2outputCmd("ipfs", root) - res.SetOutput(&rootCmd) + rootCmd.showOpts, _, _ = req.Option(flagsOptionName).Bool() + err := res.Emit(&rootCmd) + if err != nil { + log.Error(err) + } }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - v := res.Output().(*Command) - showOptions, _, _ := res.Request().Option(flagsOptionName).Bool() - buf := new(bytes.Buffer) - for _, s := range cmdPathStrings(v, showOptions) { - buf.Write([]byte(s + "\n")) - } - return buf, nil + Encoders: cmds.EncoderMap{ + cmds.Text: func(req cmds.Request) func(io.Writer) cmds.Encoder { + return func(w io.Writer) cmds.Encoder { return &commandEncoder{w} } }, }, Type: Command{}, @@ -64,6 +92,43 @@ func cmd2outputCmd(name string, cmd *cmds.Command) Command { opts[i] = Option{opt.Names()} } + output := Command{ + Name: name, + Subcommands: make([]Command, len(cmd.Subcommands)+len(cmd.OldSubcommands)), + Options: opts, + } + + // we need to keep track of names because a name *might* be used by both a Subcommand and an OldSubscommand. + names := make(map[string]struct{}) + + i := 0 + for name, sub := range cmd.Subcommands { + names[name] = struct{}{} + output.Subcommands[i] = cmd2outputCmd(name, sub) + i++ + } + + for name, sub := range cmd.OldSubcommands { + if _, ok := names[name]; ok { + continue + } + + names[name] = struct{}{} + output.Subcommands[i] = oldCmd2outputCmd(name, sub) + i++ + } + + // trucate to the amount of names we actually have + output.Subcommands = output.Subcommands[:len(names)] + return output +} + +func oldCmd2outputCmd(name string, cmd *oldcmds.Command) Command { + opts := make([]Option, len(cmd.Options)) + for i, opt := range cmd.Options { + opts[i] = Option{opt.Names()} + } + output := Command{ Name: name, Subcommands: make([]Command, len(cmd.Subcommands)), @@ -72,7 +137,7 @@ func cmd2outputCmd(name string, cmd *cmds.Command) Command { i := 0 for name, sub := range cmd.Subcommands { - output.Subcommands[i] = cmd2outputCmd(name, sub) + output.Subcommands[i] = oldCmd2outputCmd(name, sub) i++ } @@ -109,3 +174,21 @@ func cmdPathStrings(cmd *Command, showOptions bool) []string { sort.Sort(sort.StringSlice(cmds)) return cmds } + +// changes here will also need to be applied at +// - ./dag/dag.go +// - ./object/object.go +// - ./files/files.go +// - ./unixfs/unixfs.go +func unwrapOutput(i interface{}) (interface{}, error) { + var ( + ch <-chan interface{} + ok bool + ) + + if ch, ok = i.(<-chan interface{}); !ok { + return nil, e.TypeErr(ch, i) + } + + return <-ch, nil +} diff --git a/core/commands/config.go b/core/commands/config.go index fc14c1800..36926a9f0 100644 --- a/core/commands/config.go +++ b/core/commands/config.go @@ -12,11 +12,12 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" repo "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type ConfigField struct { @@ -25,7 +26,7 @@ type ConfigField struct { } var ConfigCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Get and set ipfs config values.", ShortDescription: ` 'ipfs config' controls configuration variables. It works like 'git config'. @@ -48,34 +49,41 @@ Set the value of the 'Datastore.Path' key: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")."), - cmds.StringArg("value", false, false, "The value to set the config entry to."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")."), + cmdkit.StringArg("value", false, false, "The value to set the config entry to."), }, - Options: []cmds.Option{ - cmds.BoolOption("bool", "Set a boolean value.").Default(false), - cmds.BoolOption("json", "Parse stringified JSON.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("bool", "Set a boolean value.").Default(false), + cmdkit.BoolOption("json", "Parse stringified JSON.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { args := req.Arguments() key := args[0] + var output *ConfigField + defer func() { + if output != nil { + res.SetOutput(output) + } else { + res.SetOutput(nil) + } + }() + // This is a temporary fix until we move the private key out of the config file switch strings.ToLower(key) { case "identity", "identity.privkey": - res.SetError(fmt.Errorf("cannot show or change private key through API"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot show or change private key through API"), cmdkit.ErrNormal) return default: } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() - - var output *ConfigField if len(args) == 2 { value := args[1] @@ -83,7 +91,7 @@ Set the value of the 'Datastore.Path' key: var jsonVal interface{} if err := json.Unmarshal([]byte(value), &jsonVal); err != nil { err = fmt.Errorf("failed to unmarshal json. %s", err) - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -97,10 +105,9 @@ Set the value of the 'Datastore.Path' key: output, err = getConfig(r, key) } if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(output) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { @@ -108,14 +115,18 @@ Set the value of the 'Datastore.Path' key: return nil, nil // dont output anything } - v := res.Output() - if v == nil { - k := res.Request().Arguments()[0] - return nil, fmt.Errorf("config does not contain key: %s", k) + if res.Error() != nil { + return nil, res.Error() } + + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + vf, ok := v.(*ConfigField) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(vf, v) } buf, err := config.HumanOutput(vf.Value) @@ -135,7 +146,7 @@ Set the value of the 'Datastore.Path' key: } var configShowCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Output config file contents.", ShortDescription: ` WARNING: Your private key is stored in the config file, and it will be @@ -146,32 +157,32 @@ included in the output of this command. Run: func(req cmds.Request, res cmds.Response) { fname, err := config.Filename(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } data, err := ioutil.ReadFile(fname) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } var cfg map[string]interface{} err = json.Unmarshal(data, &cfg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = scrubValue(cfg, []string{config.IdentityTag, config.PrivKeyTag}) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } output, err := config.HumanOutput(cfg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -221,7 +232,7 @@ func scrubValue(m map[string]interface{}, key []string) error { } var configEditCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Open the config file for editing in $EDITOR.", ShortDescription: ` To use 'ipfs config edit', you must have the $EDITOR environment @@ -232,19 +243,19 @@ variable set to your preferred text editor. Run: func(req cmds.Request, res cmds.Response) { filename, err := config.Filename(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = editConfig(filename) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) } }, } var configReplaceCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Replace the config with .", ShortDescription: ` Make sure to back up the config file first if necessary, as this operation @@ -252,27 +263,30 @@ can't be undone. `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("file", true, false, "The file to use as the new config."), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("file", true, false, "The file to use as the new config."), }, Run: func(req cmds.Request, res cmds.Response) { + // has to be called + res.SetOutput(nil) + r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() file, err := req.Files().NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer file.Close() err = replaceConfig(r, file) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } }, diff --git a/core/commands/dag/dag.go b/core/commands/dag/dag.go index e2d106196..7fc0a2cbd 100644 --- a/core/commands/dag/dag.go +++ b/core/commands/dag/dag.go @@ -8,18 +8,19 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" - files "github.com/ipfs/go-ipfs/commands/files" + e "github.com/ipfs/go-ipfs/core/commands/e" coredag "github.com/ipfs/go-ipfs/core/coredag" path "github.com/ipfs/go-ipfs/path" pin "github.com/ipfs/go-ipfs/pin" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash" ) var DagCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with ipld dag objects.", ShortDescription: ` 'ipfs dag' is used for creating and manipulating dag objects. @@ -47,26 +48,26 @@ type ResolveOutput struct { } var DagPutCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Add a dag node to ipfs.", ShortDescription: ` 'ipfs dag put' accepts input from a file or stdin and parses it into an object of the specified format. `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("object data", true, true, "The object to put").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("object data", true, true, "The object to put").EnableStdin(), }, - Options: []cmds.Option{ - cmds.StringOption("format", "f", "Format that the object will be added as.").Default("cbor"), - cmds.StringOption("input-enc", "Format that the input object will be.").Default("json"), - cmds.BoolOption("pin", "Pin this object when adding.").Default(false), - cmds.StringOption("hash", "Hash function to use").Default(""), + Options: []cmdkit.Option{ + cmdkit.StringOption("format", "f", "Format that the object will be added as.").Default("cbor"), + cmdkit.StringOption("input-enc", "Format that the input object will be.").Default("json"), + cmdkit.BoolOption("pin", "Pin this object when adding.").Default(false), + cmdkit.StringOption("hash", "Hash function to use").Default(""), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -75,7 +76,7 @@ into an object of the specified format. hash, _, err := req.Option("hash").String() dopin, _, err := req.Option("pin").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -87,7 +88,8 @@ into an object of the specified format. var ok bool mhType, ok = mh.Names[hash] if !ok { - res.SetError(fmt.Errorf("%s in not a valid multihash name", hash), cmds.ErrNormal) + res.SetError(fmt.Errorf("%s in not a valid multihash name", hash), cmdkit.ErrNormal) + return } } @@ -152,7 +154,7 @@ into an object of the specified format. go func() { defer close(outChan) if err := addAllAndPin(req.Files()); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } }() @@ -160,56 +162,48 @@ into an object of the specified format. Type: OutputObject{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + oobj, ok := v.(*OutputObject) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(oobj, v) } - marshal := func(v interface{}) (io.Reader, error) { - obj, ok := v.(*OutputObject) - if !ok { - return nil, u.ErrCast() - } - - return strings.NewReader(obj.Cid.String() + "\n"), nil - } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil + return strings.NewReader(oobj.Cid.String() + "\n"), nil }, }, } var DagGetCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Get a dag node from ipfs.", ShortDescription: ` 'ipfs dag get' fetches a dag node from ipfs and prints it out in the specifed format. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ref", true, false, "The object to get").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ref", true, false, "The object to get").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } p, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } obj, rem, err := n.Resolver.ResolveToLastNode(req.Context(), p) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -217,7 +211,7 @@ format. if len(rem) > 0 { final, _, err := obj.Resolve(rem) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } out = final @@ -229,31 +223,31 @@ format. // DagResolveCmd returns address of highest block within a path and a path remainder var DagResolveCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Resolve ipld block", ShortDescription: ` 'ipfs dag resolve' fetches a dag node from ipfs, prints it's address and remaining path. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ref", true, false, "The path to resolve").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ref", true, false, "The path to resolve").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } p, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } obj, rem, err := n.Resolver.ResolveToLastNode(req.Context(), p) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -264,7 +258,12 @@ var DagResolveCmd = &cmds.Command{ }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - output := res.Output().(*ResolveOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + output := v.(*ResolveOutput) buf := new(bytes.Buffer) p := output.Cid.String() if output.RemPath != "" { @@ -278,3 +277,17 @@ var DagResolveCmd = &cmds.Command{ }, Type: ResolveOutput{}, } + +// copy+pasted from ../commands.go +func unwrapOutput(i interface{}) (interface{}, error) { + var ( + ch <-chan interface{} + ok bool + ) + + if ch, ok = i.(<-chan interface{}); !ok { + return nil, e.TypeErr(ch, i) + } + + return <-ch, nil +} diff --git a/core/commands/dht.go b/core/commands/dht.go index e2f9ea47f..b6000e406 100644 --- a/core/commands/dht.go +++ b/core/commands/dht.go @@ -9,6 +9,7 @@ import ( "time" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" @@ -16,7 +17,7 @@ import ( routing "gx/ipfs/QmPR2JzfKd9poHx9XBhzoFeBBC31ZM3W5iUPKJZWyaoZZm/go-libp2p-routing" notif "gx/ipfs/QmPR2JzfKd9poHx9XBhzoFeBBC31ZM3W5iUPKJZWyaoZZm/go-libp2p-routing/notifications" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58" ipdht "gx/ipfs/QmWRBYr99v8sjrpbyNWMuGkQekn7b9ELoLSCe8Ny7Nxain/go-libp2p-kad-dht" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" @@ -25,7 +26,7 @@ import ( var ErrNotDHT = errors.New("routing service is not a DHT") var DhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Issue commands directly through the DHT.", ShortDescription: ``, }, @@ -41,27 +42,27 @@ var DhtCmd = &cmds.Command{ } var queryDhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Find the closest Peer IDs to a given Peer ID by querying the DHT.", ShortDescription: "Outputs a list of newline-delimited Peer IDs.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("peerID", true, true, "The peerID to run the query against."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peerID", true, true, "The peerID to run the query against."), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dht, ok := n.Routing.(*ipdht.IpfsDHT) if !ok { - res.SetError(ErrNotDHT, cmds.ErrNormal) + res.SetError(ErrNotDHT, cmdkit.ErrNormal) return } @@ -72,7 +73,7 @@ var queryDhtCmd = &cmds.Command{ closestPeers, err := dht.GetClosestPeers(ctx, k) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -97,12 +98,7 @@ var queryDhtCmd = &cmds.Command{ }() }, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - + cmds.Text: func() cmds.Marshaler { pfm := pfuncMap{ notif.PeerResponse: func(obj *notif.QueryEvent, out io.Writer, verbose bool) { for _, p := range obj.Responses { @@ -111,10 +107,15 @@ var queryDhtCmd = &cmds.Command{ }, } - marshal := func(v interface{}) (io.Reader, error) { + return func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + obj, ok := v.(*notif.QueryEvent) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } verbose, _, _ := res.Request().Option("v").Bool() @@ -123,50 +124,44 @@ var queryDhtCmd = &cmds.Command{ printEvent(obj, buf, verbose, pfm) return buf, nil } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - }, + }(), }, Type: notif.QueryEvent{}, } var findProvidersDhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Find peers in the DHT that can provide a specific value, given a key.", ShortDescription: "Outputs a list of newline-delimited provider Peer IDs.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, true, "The key to find providers for."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, true, "The key to find providers for."), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), - cmds.IntOption("num-providers", "n", "The number of providers to find.").Default(20), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), + cmdkit.IntOption("num-providers", "n", "The number of providers to find.").Default(20), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dht, ok := n.Routing.(*ipdht.IpfsDHT) if !ok { - res.SetError(ErrNotDHT, cmds.ErrNormal) + res.SetError(ErrNotDHT, cmdkit.ErrNormal) return } numProviders, _, err := res.Request().Option("num-providers").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if numProviders < 1 { - res.SetError(fmt.Errorf("Number of providers must be greater than 0"), cmds.ErrNormal) + res.SetError(fmt.Errorf("Number of providers must be greater than 0"), cmdkit.ErrNormal) return } @@ -178,7 +173,7 @@ var findProvidersDhtCmd = &cmds.Command{ c, err := cid.Decode(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -202,13 +197,7 @@ var findProvidersDhtCmd = &cmds.Command{ }() }, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - - verbose, _, _ := res.Request().Option("v").Bool() + cmds.Text: func() func(cmds.Response) (io.Reader, error) { pfm := pfuncMap{ notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) { if verbose { @@ -229,53 +218,53 @@ var findProvidersDhtCmd = &cmds.Command{ }, } - marshal := func(v interface{}) (io.Reader, error) { + return func(res cmds.Response) (io.Reader, error) { + verbose, _, _ := res.Request().Option("v").Bool() + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + obj, ok := v.(*notif.QueryEvent) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } buf := new(bytes.Buffer) printEvent(obj, buf, verbose, pfm) return buf, nil } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - }, + }(), }, Type: notif.QueryEvent{}, } var provideRefDhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Announce to the network that you are providing given values.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, true, "The key[s] to send provide records for.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, true, "The key[s] to send provide records for.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), - cmds.BoolOption("recursive", "r", "Recursively provide entire graph.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), + cmdkit.BoolOption("recursive", "r", "Recursively provide entire graph.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.Routing == nil { - res.SetError(errNotOnline, cmds.ErrNormal) + res.SetError(errNotOnline, cmdkit.ErrNormal) return } if len(n.PeerHost.Network().Conns()) == 0 { - res.SetError(errors.New("cannot provide, no connected peers"), cmds.ErrNormal) + res.SetError(errors.New("cannot provide, no connected peers"), cmdkit.ErrNormal) return } @@ -285,18 +274,18 @@ var provideRefDhtCmd = &cmds.Command{ for _, arg := range req.Arguments() { c, err := cid.Decode(arg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } has, err := n.Blockstore.Has(c) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !has { - res.SetError(fmt.Errorf("block %s not found locally, cannot provide", c), cmds.ErrNormal) + res.SetError(fmt.Errorf("block %s not found locally, cannot provide", c), cmdkit.ErrNormal) return } @@ -333,13 +322,7 @@ var provideRefDhtCmd = &cmds.Command{ }() }, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - - verbose, _, _ := res.Request().Option("v").Bool() + cmds.Text: func() func(res cmds.Response) (io.Reader, error) { pfm := pfuncMap{ notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) { if verbose { @@ -348,23 +331,22 @@ var provideRefDhtCmd = &cmds.Command{ }, } - marshal := func(v interface{}) (io.Reader, error) { + return func(res cmds.Response) (io.Reader, error) { + verbose, _, _ := res.Request().Option("v").Bool() + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } obj, ok := v.(*notif.QueryEvent) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } buf := new(bytes.Buffer) printEvent(obj, buf, verbose, pfm) return buf, nil } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - }, + }(), }, Type: notif.QueryEvent{}, } @@ -406,33 +388,33 @@ func provideKeysRec(ctx context.Context, r routing.IpfsRouting, dserv dag.DAGSer } var findPeerDhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Query the DHT for all of the multiaddresses associated with a Peer ID.", ShortDescription: "Outputs a list of newline-delimited multiaddresses.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("peerID", true, true, "The ID of the peer to search for."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peerID", true, true, "The ID of the peer to search for."), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dht, ok := n.Routing.(*ipdht.IpfsDHT) if !ok { - res.SetError(ErrNotDHT, cmds.ErrNormal) + res.SetError(ErrNotDHT, cmdkit.ErrNormal) return } pid, err := peer.IDB58Decode(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -467,14 +449,7 @@ var findPeerDhtCmd = &cmds.Command{ }() }, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - - verbose, _, _ := res.Request().Option("v").Bool() - + cmds.Text: func() func(cmds.Response) (io.Reader, error) { pfm := pfuncMap{ notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) { pi := obj.Responses[0] @@ -483,29 +458,31 @@ var findPeerDhtCmd = &cmds.Command{ } }, } - marshal := func(v interface{}) (io.Reader, error) { + + return func(res cmds.Response) (io.Reader, error) { + verbose, _, _ := res.Request().Option("v").Bool() + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + obj, ok := v.(*notif.QueryEvent) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } buf := new(bytes.Buffer) printEvent(obj, buf, verbose, pfm) + return buf, nil } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - }, + }(), }, Type: notif.QueryEvent{}, } var getValueDhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Given a key, query the DHT for its best value.", ShortDescription: ` Outputs the best value for the given key. @@ -518,22 +495,22 @@ Different key types can specify other 'best' rules. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, true, "The key to find a value for."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, true, "The key to find a value for."), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dht, ok := n.Routing.(*ipdht.IpfsDHT) if !ok { - res.SetError(ErrNotDHT, cmds.ErrNormal) + res.SetError(ErrNotDHT, cmdkit.ErrNormal) return } @@ -545,7 +522,7 @@ Different key types can specify other 'best' rules. dhtkey, err := escapeDhtKey(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -573,14 +550,7 @@ Different key types can specify other 'best' rules. }() }, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - - verbose, _, _ := res.Request().Option("v").Bool() - + cmds.Text: func() func(cmds.Response) (io.Reader, error) { pfm := pfuncMap{ notif.Value: func(obj *notif.QueryEvent, out io.Writer, verbose bool) { if verbose { @@ -590,10 +560,17 @@ Different key types can specify other 'best' rules. } }, } - marshal := func(v interface{}) (io.Reader, error) { + + return func(res cmds.Response) (io.Reader, error) { + verbose, _, _ := res.Request().Option("v").Bool() + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + obj, ok := v.(*notif.QueryEvent) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } buf := new(bytes.Buffer) @@ -602,19 +579,13 @@ Different key types can specify other 'best' rules. return buf, nil } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - }, + }(), }, Type: notif.QueryEvent{}, } var putValueDhtCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Write a key/value pair to the DHT.", ShortDescription: ` Given a key of the form /foo/bar and a value of any form, this will write that @@ -635,23 +606,23 @@ NOTE: A value may not exceed 2048 bytes. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "The key to store the value at."), - cmds.StringArg("value", true, false, "The value to store.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "The key to store the value at."), + cmdkit.StringArg("value", true, false, "The value to store.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dht, ok := n.Routing.(*ipdht.IpfsDHT) if !ok { - res.SetError(ErrNotDHT, cmds.ErrNormal) + res.SetError(ErrNotDHT, cmdkit.ErrNormal) return } @@ -663,7 +634,7 @@ NOTE: A value may not exceed 2048 bytes. key, err := escapeDhtKey(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -688,13 +659,7 @@ NOTE: A value may not exceed 2048 bytes. }() }, Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - - verbose, _, _ := res.Request().Option("v").Bool() + cmds.Text: func() func(cmds.Response) (io.Reader, error) { pfm := pfuncMap{ notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) { if verbose { @@ -706,10 +671,15 @@ NOTE: A value may not exceed 2048 bytes. }, } - marshal := func(v interface{}) (io.Reader, error) { + return func(res cmds.Response) (io.Reader, error) { + verbose, _, _ := res.Request().Option("v").Bool() + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } obj, ok := v.(*notif.QueryEvent) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } buf := new(bytes.Buffer) @@ -717,13 +687,7 @@ NOTE: A value may not exceed 2048 bytes. return buf, nil } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - }, + }(), }, Type: notif.QueryEvent{}, } diff --git a/core/commands/diag.go b/core/commands/diag.go index cc4602489..b3c6df24d 100644 --- a/core/commands/diag.go +++ b/core/commands/diag.go @@ -1,9 +1,13 @@ package commands -import cmds "github.com/ipfs/go-ipfs/commands" +import ( + cmds "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" +) var DiagCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Generate diagnostic reports.", }, diff --git a/core/commands/dns.go b/core/commands/dns.go index 09292da8d..c02c6f9c4 100644 --- a/core/commands/dns.go +++ b/core/commands/dns.go @@ -5,12 +5,14 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" namesys "github.com/ipfs/go-ipfs/namesys" - util "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var DNSCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Resolve DNS links.", ShortDescription: ` Multihashes are hard to remember, but domain names are usually easy to @@ -43,11 +45,11 @@ The resolver can recursively resolve: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("domain-name", true, false, "The domain-name name to resolve.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("domain-name", true, false, "The domain-name name to resolve.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Resolve until the result is not a DNS link.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("recursive", "r", "Resolve until the result is not a DNS link.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { @@ -61,20 +63,25 @@ The resolver can recursively resolve: } output, err := resolver.ResolveN(req.Context(), name, depth) if err == namesys.ErrResolveFailed { - res.SetError(err, cmds.ErrNotFound) + res.SetError(err, cmdkit.ErrNotFound) return } if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&ResolvedPath{output}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - output, ok := res.Output().(*ResolvedPath) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + output, ok := v.(*ResolvedPath) if !ok { - return nil, util.ErrCast() + return nil, e.TypeErr(output, v) } return strings.NewReader(output.Path.String() + "\n"), nil }, diff --git a/core/commands/e/error.go b/core/commands/e/error.go new file mode 100644 index 000000000..c8bfa11c1 --- /dev/null +++ b/core/commands/e/error.go @@ -0,0 +1,30 @@ +package e + +import ( + "fmt" + "runtime/debug" +) + +// TypeErr returns an error with a string that explains what error was expected and what was received. +func TypeErr(expected, actual interface{}) error { + return fmt.Errorf("expected type %T, got %T", expected, actual) +} + +// compile time type check that HandlerError is an error +var _ error = New(nil) + +// HandlerError is adds a stack trace to an error +type HandlerError struct { + Err error + Stack []byte +} + +// Error makes HandlerError implement error +func (err HandlerError) Error() string { + return fmt.Sprintf("%s in:\n%s", err.Err.Error(), err.Stack) +} + +// New returns a new HandlerError +func New(err error) HandlerError { + return HandlerError{Err: err, Stack: debug.Stack()} +} diff --git a/core/commands/external.go b/core/commands/external.go index d4dc56d54..f6c1eeb57 100644 --- a/core/commands/external.go +++ b/core/commands/external.go @@ -9,12 +9,14 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) func ExternalBinary() *cmds.Command { return &cmds.Command{ - Arguments: []cmds.Argument{ - cmds.StringArg("args", false, true, "Arguments for subcommand."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("args", false, true, "Arguments for subcommand."), }, External: true, Run: func(req cmds.Request, res cmds.Response) { @@ -33,7 +35,7 @@ func ExternalBinary() *cmds.Command { } } - res.SetError(fmt.Errorf("%s not installed.", binname), cmds.ErrNormal) + res.SetError(fmt.Errorf("%s not installed", binname), cmdkit.ErrNormal) return } @@ -59,7 +61,7 @@ func ExternalBinary() *cmds.Command { err = cmd.Start() if err != nil { - res.SetError(fmt.Errorf("failed to start subcommand: %s", err), cmds.ErrNormal) + res.SetError(fmt.Errorf("failed to start subcommand: %s", err), cmdkit.ErrNormal) return } @@ -68,7 +70,7 @@ func ExternalBinary() *cmds.Command { go func() { err = cmd.Wait() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) } w.Close() diff --git a/core/commands/files/files.go b/core/commands/files/files.go index fa784aad8..ee265e4dc 100644 --- a/core/commands/files/files.go +++ b/core/commands/files/files.go @@ -12,11 +12,13 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" dag "github.com/ipfs/go-ipfs/merkledag" mfs "github.com/ipfs/go-ipfs/mfs" path "github.com/ipfs/go-ipfs/path" ft "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" @@ -27,7 +29,7 @@ import ( var log = logging.Logger("cmds/files") var FilesCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with unixfs files.", ShortDescription: ` Files is an API for manipulating IPFS objects as if they were a unix @@ -43,8 +45,8 @@ applies to running 'ipfs repo gc' concurrently with '--flush=false' operations. `, }, - Options: []cmds.Option{ - cmds.BoolOption("f", "flush", "Flush target and ancestors after write.").Default(true), + Options: []cmdkit.Option{ + cmdkit.BoolOption("f", "flush", "Flush target and ancestors after write.").Default(true), }, Subcommands: map[string]*cmds.Command{ "read": FilesReadCmd, @@ -60,58 +62,58 @@ operations. }, } -var cidVersionOption = cmds.IntOption("cid-version", "cid-ver", "Cid version to use. (experimental)") -var hashOption = cmds.StringOption("hash", "Hash function to use. Will set Cid version to 1 if used. (experimental)") +var cidVersionOption = cmdkit.IntOption("cid-version", "cid-ver", "Cid version to use. (experimental)") +var hashOption = cmdkit.StringOption("hash", "Hash function to use. Will set Cid version to 1 if used. (experimental)") var formatError = errors.New("Format was set by multiple options. Only one format option is allowed") var FilesStatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Display file status.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", true, false, "Path to node to stat."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", true, false, "Path to node to stat."), }, - Options: []cmds.Option{ - cmds.StringOption("format", "Print statistics in given format. Allowed tokens: "+ + Options: []cmdkit.Option{ + cmdkit.StringOption("format", "Print statistics in given format. Allowed tokens: "+ " . Conflicts with other format options.").Default( ` Size: CumulativeSize: ChildBlocks: Type: `), - cmds.BoolOption("hash", "Print only hash. Implies '--format='. Conflicts with other format options.").Default(false), - cmds.BoolOption("size", "Print only size. Implies '--format='. Conflicts with other format options.").Default(false), + cmdkit.BoolOption("hash", "Print only hash. Implies '--format='. Conflicts with other format options.").Default(false), + cmdkit.BoolOption("size", "Print only size. Implies '--format='. Conflicts with other format options.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { _, err := statGetFormatOptions(req) if err != nil { - res.SetError(err, cmds.ErrClient) + res.SetError(err, cmdkit.ErrClient) } node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } path, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fsn, err := mfs.Lookup(node.FilesRoot, path) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } o, err := statNode(node.DAG, fsn) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -119,8 +121,15 @@ Type: `), }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } - out := res.Output().(*Object) + out, ok := v.(*Object) + if !ok { + return nil, e.TypeErr(out, v) + } buf := new(bytes.Buffer) s, _ := statGetFormatOptions(res.Request()) @@ -211,17 +220,17 @@ func statNode(ds dag.DAGService, fsn mfs.FSNode) (*Object, error) { } var FilesCpCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Copy files into mfs.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("source", true, false, "Source object to copy."), - cmds.StringArg("dest", true, false, "Destination to copy object to."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("source", true, false, "Source object to copy."), + cmdkit.StringArg("dest", true, false, "Destination to copy object to."), }, Run: func(req cmds.Request, res cmds.Response) { node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -229,14 +238,14 @@ var FilesCpCmd = &cmds.Command{ src, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } src = strings.TrimRight(src, "/") dst, err := checkPath(req.Arguments()[1]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -246,23 +255,25 @@ var FilesCpCmd = &cmds.Command{ nd, err := getNodeFromPath(req.Context(), node, src) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = mfs.PutNode(node.FilesRoot, dst, nd) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if flush { err := mfs.FlushPath(node.FilesRoot, dst) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } + + res.SetOutput(nil) }, } @@ -303,7 +314,7 @@ type FilesLsOutput struct { } var FilesLsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List directories in the local mutable namespace.", ShortDescription: ` List directories in the local mutable namespace. @@ -323,11 +334,11 @@ Examples: bar `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", false, false, "Path to show listing for. Defaults to '/'."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", false, false, "Path to show listing for. Defaults to '/'."), }, - Options: []cmds.Option{ - cmds.BoolOption("l", "Use long listing format."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("l", "Use long listing format."), }, Run: func(req cmds.Request, res cmds.Response) { var arg string @@ -340,19 +351,19 @@ Examples: path, err := checkPath(arg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fsn, err := mfs.Lookup(nd.FilesRoot, path) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -364,7 +375,7 @@ Examples: var output []mfs.NodeListing names, err := fsn.ListNames(req.Context()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -377,7 +388,7 @@ Examples: } else { listing, err := fsn.List(req.Context()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&FilesLsOutput{listing}) @@ -389,12 +400,21 @@ Examples: res.SetOutput(out) return default: - res.SetError(errors.New("unrecognized type"), cmds.ErrNormal) + res.SetError(errors.New("unrecognized type"), cmdkit.ErrNormal) } }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - out := res.Output().(*FilesLsOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*FilesLsOutput) + if !ok { + return nil, e.TypeErr(out, v) + } + buf := new(bytes.Buffer) long, _, _ := res.Request().Option("l").Bool() @@ -412,7 +432,7 @@ Examples: } var FilesReadCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Read a file in a given mfs.", ShortDescription: ` Read a specified number of bytes from a file at a given offset. By default, @@ -425,41 +445,41 @@ Examples: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", true, false, "Path to file to be read."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", true, false, "Path to file to be read."), }, - Options: []cmds.Option{ - cmds.IntOption("offset", "o", "Byte offset to begin reading from."), - cmds.IntOption("count", "n", "Maximum number of bytes to read."), + Options: []cmdkit.Option{ + cmdkit.IntOption("offset", "o", "Byte offset to begin reading from."), + cmdkit.IntOption("count", "n", "Maximum number of bytes to read."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } path, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fsn, err := mfs.Lookup(n.FilesRoot, path) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fi, ok := fsn.(*mfs.File) if !ok { - res.SetError(fmt.Errorf("%s was not a file.", path), cmds.ErrNormal) + res.SetError(fmt.Errorf("%s was not a file.", path), cmdkit.ErrNormal) return } rfd, err := fi.Open(mfs.OpenReadOnly, false) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -467,40 +487,40 @@ Examples: offset, _, err := req.Option("offset").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if offset < 0 { - res.SetError(fmt.Errorf("Cannot specify negative offset."), cmds.ErrNormal) + res.SetError(fmt.Errorf("Cannot specify negative offset."), cmdkit.ErrNormal) return } filen, err := rfd.Size() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if int64(offset) > filen { - res.SetError(fmt.Errorf("Offset was past end of file (%d > %d).", offset, filen), cmds.ErrNormal) + res.SetError(fmt.Errorf("Offset was past end of file (%d > %d).", offset, filen), cmdkit.ErrNormal) return } _, err = rfd.Seek(int64(offset), io.SeekStart) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } var r io.Reader = &contextReaderWrapper{R: rfd, ctx: req.Context()} count, found, err := req.Option("count").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if found { if count < 0 { - res.SetError(fmt.Errorf("Cannot specify negative 'count'."), cmds.ErrNormal) + res.SetError(fmt.Errorf("Cannot specify negative 'count'."), cmdkit.ErrNormal) return } r = io.LimitReader(r, int64(count)) @@ -524,7 +544,7 @@ func (crw *contextReaderWrapper) Read(b []byte) (int, error) { } var FilesMvCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Move files.", ShortDescription: ` Move files around. Just like traditional unix mv. @@ -536,38 +556,40 @@ Example: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("source", true, false, "Source file to move."), - cmds.StringArg("dest", true, false, "Destination path for file to be moved to."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("source", true, false, "Source file to move."), + cmdkit.StringArg("dest", true, false, "Destination path for file to be moved to."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } src, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dst, err := checkPath(req.Arguments()[1]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = mfs.Mv(n.FilesRoot, src, dst) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } + + res.SetOutput(nil) }, } var FilesWriteCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Write to a mutable file in a given filesystem.", ShortDescription: ` Write data to a file in a given filesystem. This command allows you to specify @@ -600,23 +622,23 @@ the tree has been flushed. This can be accomplished by running 'ipfs files stat' on the file or any of its ancestors. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", true, false, "Path to write to."), - cmds.FileArg("data", true, false, "Data to write.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", true, false, "Path to write to."), + cmdkit.FileArg("data", true, false, "Data to write.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.IntOption("offset", "o", "Byte offset to begin writing at."), - cmds.BoolOption("create", "e", "Create the file if it does not exist."), - cmds.BoolOption("truncate", "t", "Truncate the file to size zero before writing."), - cmds.IntOption("count", "n", "Maximum number of bytes to read."), - cmds.BoolOption("raw-leaves", "Use raw blocks for newly created leaf nodes. (experimental)"), + Options: []cmdkit.Option{ + cmdkit.IntOption("offset", "o", "Byte offset to begin writing at."), + cmdkit.BoolOption("create", "e", "Create the file if it does not exist."), + cmdkit.BoolOption("truncate", "t", "Truncate the file to size zero before writing."), + cmdkit.IntOption("count", "n", "Maximum number of bytes to read."), + cmdkit.BoolOption("raw-leaves", "Use raw blocks for newly created leaf nodes. (experimental)"), cidVersionOption, hashOption, }, Run: func(req cmds.Request, res cmds.Response) { path, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -627,29 +649,29 @@ stat' on the file or any of its ancestors. prefix, err := getPrefix(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } offset, _, err := req.Option("offset").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if offset < 0 { - res.SetError(fmt.Errorf("cannot have negative write offset"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot have negative write offset"), cmdkit.ErrNormal) return } fi, err := getFileHandle(nd.FilesRoot, path, create, prefix) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if rawLeavesDef { @@ -658,44 +680,44 @@ stat' on the file or any of its ancestors. wfd, err := fi.Open(mfs.OpenWriteOnly, flush) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer func() { err := wfd.Close() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) } }() if trunc { if err := wfd.Truncate(0); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } count, countfound, err := req.Option("count").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if countfound && count < 0 { - res.SetError(fmt.Errorf("cannot have negative byte count"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot have negative byte count"), cmdkit.ErrNormal) return } _, err = wfd.Seek(int64(offset), io.SeekStart) if err != nil { log.Error("seekfail: ", err) - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } input, err := req.Files().NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -704,18 +726,18 @@ stat' on the file or any of its ancestors. r = io.LimitReader(r, int64(count)) } - n, err := io.Copy(wfd, r) + _, err = io.Copy(wfd, r) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - log.Debugf("wrote %d bytes to %s", n, path) + res.SetOutput(nil) }, } var FilesMkdirCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Make directories.", ShortDescription: ` Create the directory if it does not already exist. @@ -732,25 +754,25 @@ Examples: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", true, false, "Path to dir to make."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", true, false, "Path to dir to make."), }, - Options: []cmds.Option{ - cmds.BoolOption("parents", "p", "No error if existing, make parent directories as needed."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("parents", "p", "No error if existing, make parent directories as needed."), cidVersionOption, hashOption, }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dashp, _, _ := req.Option("parents").Bool() dirtomake, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -758,7 +780,7 @@ Examples: prefix, err := getPrefix(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } root := n.FilesRoot @@ -769,28 +791,28 @@ Examples: Prefix: prefix, }) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - + res.SetOutput(nil) }, } var FilesFlushCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Flush a given path's data to disk.", ShortDescription: ` Flush a given path to disk. This is only useful when other commands are run with the '--flush=false'. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", false, false, "Path to flush. Default: '/'."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", false, false, "Path to flush. Default: '/'."), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -801,30 +823,32 @@ are run with the '--flush=false'. err = mfs.FlushPath(nd.FilesRoot, path) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } + + res.SetOutput(nil) }, } var FilesChcidCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Change the cid version or hash function of the root node of a given path.", ShortDescription: ` Change the cid version or hash function of the root node of a given path. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", false, false, "Path to change. Default: '/'."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", false, false, "Path to change. Default: '/'."), }, - Options: []cmds.Option{ + Options: []cmdkit.Option{ cidVersionOption, hashOption, }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -837,13 +861,13 @@ Change the cid version or hash function of the root node of a given path. prefix, err := getPrefix(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = updatePath(nd.FilesRoot, path, prefix, flush) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } }, @@ -874,7 +898,7 @@ func updatePath(rt *mfs.Root, pth string, prefix *cid.Prefix, flush bool) error } var FilesRmCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove a file.", ShortDescription: ` Remove files or directories. @@ -888,27 +912,29 @@ Remove files or directories. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", true, true, "File to remove."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", true, true, "File to remove."), }, - Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Recursively remove directories."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("recursive", "r", "Recursively remove directories."), }, Run: func(req cmds.Request, res cmds.Response) { + defer res.SetOutput(nil) + nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } path, err := checkPath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if path == "/" { - res.SetError(fmt.Errorf("cannot delete root"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot delete root"), cmdkit.ErrNormal) return } @@ -920,13 +946,13 @@ Remove files or directories. dir, name := gopath.Split(path) parent, err := mfs.Lookup(nd.FilesRoot, dir) if err != nil { - res.SetError(fmt.Errorf("parent lookup: %s", err), cmds.ErrNormal) + res.SetError(fmt.Errorf("parent lookup: %s", err), cmdkit.ErrNormal) return } pdir, ok := parent.(*mfs.Directory) if !ok { - res.SetError(fmt.Errorf("No such file or directory: %s", path), cmds.ErrNormal) + res.SetError(fmt.Errorf("No such file or directory: %s", path), cmdkit.ErrNormal) return } @@ -937,7 +963,7 @@ Remove files or directories. if success { err := pdir.Flush() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -947,7 +973,7 @@ Remove files or directories. if dashr { err := pdir.Unlink(name) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -957,18 +983,18 @@ Remove files or directories. childi, err := pdir.Child(name) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } switch childi.(type) { case *mfs.Directory: - res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmds.ErrNormal) + res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmdkit.ErrNormal) return default: err := pdir.Unlink(name) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -1074,3 +1100,17 @@ func checkPath(p string) (string, error) { } return cleaned, nil } + +// copy+pasted from ../commands.go +func unwrapOutput(i interface{}) (interface{}, error) { + var ( + ch <-chan interface{} + ok bool + ) + + if ch, ok = i.(<-chan interface{}); !ok { + return nil, e.TypeErr(ch, i) + } + + return <-ch, nil +} diff --git a/core/commands/filestore.go b/core/commands/filestore.go index d07ffc310..79ea730d2 100644 --- a/core/commands/filestore.go +++ b/core/commands/filestore.go @@ -4,27 +4,38 @@ import ( "context" "fmt" "io" + "os" - cmds "github.com/ipfs/go-ipfs/commands" + oldCmds "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" "github.com/ipfs/go-ipfs/filestore" + cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var FileStoreCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with filestore objects.", }, Subcommands: map[string]*cmds.Command{ - "ls": lsFileStore, + "ls": lsFileStore, + }, + OldSubcommands: map[string]*oldCmds.Command{ "verify": verifyFileStore, "dups": dupsFileStore, }, } +type lsEncoder struct { + errors bool + w io.Writer +} + var lsFileStore = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List objects in filestore.", LongDescription: ` List objects in the filestore. @@ -37,62 +48,84 @@ The output is: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("obj", false, true, "Cid of objects to list."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("obj", false, true, "Cid of objects to list."), }, - Options: []cmds.Option{ - cmds.BoolOption("file-order", "sort the results based on the path of the backing file"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("file-order", "sort the results based on the path of the backing file"), }, - Run: func(req cmds.Request, res cmds.Response) { - _, fs, err := getFilestore(req) + Run: func(req cmds.Request, res cmds.ResponseEmitter) { + _, fs, err := getFilestore(req.InvocContext()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } args := req.Arguments() if len(args) > 0 { - out := perKeyActionToChan(args, func(c *cid.Cid) *filestore.ListRes { + out := perKeyActionToChan(req.Context(), args, func(c *cid.Cid) *filestore.ListRes { return filestore.List(fs, c) - }, req.Context()) - res.SetOutput(out) + }) + + err = res.Emit(out) + if err != nil { + log.Error(err) + } } else { fileOrder, _, _ := req.Option("file-order").Bool() next, err := filestore.ListAll(fs, fileOrder) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - out := listResToChan(next, req.Context()) - res.SetOutput(out) + + out := listResToChan(req.Context(), next) + err = res.Emit(out) + if err != nil { + log.Error(err) + } } }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - errors := false - for r0 := range outChan { - r := r0.(*filestore.ListRes) - if r.ErrorMsg != "" { - errors = true - fmt.Fprintf(res.Stderr(), "%s\n", r.ErrorMsg) - } else { - fmt.Fprintf(res.Stdout(), "%s\n", r.FormatLong()) + PostRun: cmds.PostRunMap{ + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter { + reNext, res := cmds.NewChanResponsePair(req) + + go func() { + defer re.Close() + + var errors bool + for { + v, err := res.Next() + if !cmds.HandleError(err, res, re) { + break + } + + r, ok := v.(*filestore.ListRes) + if !ok { + log.Error(e.New(e.TypeErr(r, v))) + return + } + + if r.ErrorMsg != "" { + errors = true + fmt.Fprintf(os.Stderr, "%s\n", r.ErrorMsg) + } else { + fmt.Fprintf(os.Stdout, "%s\n", r.FormatLong()) + } } - } - if errors { - return nil, fmt.Errorf("errors while displaying some entries") - } - return nil, nil + + if errors { + re.SetError("errors while displaying some entries", cmdkit.ErrNormal) + } + }() + + return reNext }, }, Type: filestore.ListRes{}, } -var verifyFileStore = &cmds.Command{ - Helptext: cmds.HelpText{ +var verifyFileStore = &oldCmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Verify objects in filestore.", LongDescription: ` Verify objects in the filestore. @@ -115,68 +148,70 @@ ERROR: internal error, most likely due to a corrupt database For ERROR entries the error will also be printed to stderr. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("obj", false, true, "Cid of objects to verify."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("obj", false, true, "Cid of objects to verify."), }, - Options: []cmds.Option{ - cmds.BoolOption("file-order", "verify the objects based on the order of the backing file"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("file-order", "verify the objects based on the order of the backing file"), }, - Run: func(req cmds.Request, res cmds.Response) { - _, fs, err := getFilestore(req) + Run: func(req oldCmds.Request, res oldCmds.Response) { + _, fs, err := getFilestore(req.InvocContext()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } args := req.Arguments() if len(args) > 0 { - out := perKeyActionToChan(args, func(c *cid.Cid) *filestore.ListRes { + out := perKeyActionToChan(req.Context(), args, func(c *cid.Cid) *filestore.ListRes { return filestore.Verify(fs, c) - }, req.Context()) + }) res.SetOutput(out) } else { fileOrder, _, _ := req.Option("file-order").Bool() next, err := filestore.VerifyAll(fs, fileOrder) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - out := listResToChan(next, req.Context()) + out := listResToChan(req.Context(), next) res.SetOutput(out) } }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) + Marshalers: oldCmds.MarshalerMap{ + oldCmds.Text: func(res oldCmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + r, ok := v.(*filestore.ListRes) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(r, v) } - res.SetOutput(nil) - for r0 := range outChan { - r := r0.(*filestore.ListRes) - if r.Status == filestore.StatusOtherError { - fmt.Fprintf(res.Stderr(), "%s\n", r.ErrorMsg) - } - fmt.Fprintf(res.Stdout(), "%s %s\n", r.Status.Format(), r.FormatLong()) + + if r.Status == filestore.StatusOtherError { + fmt.Fprintf(res.Stderr(), "%s\n", r.ErrorMsg) } + fmt.Fprintf(res.Stdout(), "%s %s\n", r.Status.Format(), r.FormatLong()) return nil, nil }, }, Type: filestore.ListRes{}, } -var dupsFileStore = &cmds.Command{ - Helptext: cmds.HelpText{ +var dupsFileStore = &oldCmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "List blocks that are both in the filestore and standard block storage.", }, - Run: func(req cmds.Request, res cmds.Response) { - _, fs, err := getFilestore(req) + Run: func(req oldCmds.Request, res oldCmds.Response) { + _, fs, err := getFilestore(req.InvocContext()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } ch, err := fs.FileManager().AllKeysChan(req.Context()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -201,8 +236,12 @@ var dupsFileStore = &cmds.Command{ Type: RefWrapper{}, } -func getFilestore(req cmds.Request) (*core.IpfsNode, *filestore.Filestore, error) { - n, err := req.InvocContext().GetNode() +type getNoder interface { + GetNode() (*core.IpfsNode, error) +} + +func getFilestore(g getNoder) (*core.IpfsNode, *filestore.Filestore, error) { + n, err := g.GetNode() if err != nil { return nil, nil, err } @@ -213,7 +252,7 @@ func getFilestore(req cmds.Request) (*core.IpfsNode, *filestore.Filestore, error return n, fs, err } -func listResToChan(next func() *filestore.ListRes, ctx context.Context) <-chan interface{} { +func listResToChan(ctx context.Context, next func() *filestore.ListRes) <-chan interface{} { out := make(chan interface{}, 128) go func() { defer close(out) @@ -232,7 +271,7 @@ func listResToChan(next func() *filestore.ListRes, ctx context.Context) <-chan i return out } -func perKeyActionToChan(args []string, action func(*cid.Cid) *filestore.ListRes, ctx context.Context) <-chan interface{} { +func perKeyActionToChan(ctx context.Context, args []string, action func(*cid.Cid) *filestore.ListRes) <-chan interface{} { out := make(chan interface{}, 128) go func() { defer close(out) diff --git a/core/commands/get.go b/core/commands/get.go index bc38c3000..be2f31582 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -9,20 +9,22 @@ import ( gopath "path" "strings" - "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" - - cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" tar "github.com/ipfs/go-ipfs/thirdparty/tar" uarchive "github.com/ipfs/go-ipfs/unixfs/archive" + + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" ) var ErrInvalidCompressionLevel = errors.New("Compression level must be between 1 and 9") var GetCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Download IPFS objects.", ShortDescription: ` Stores to disk the data contained an IPFS or IPNS object(s) at the given path. @@ -37,41 +39,40 @@ may also specify the level of compression by specifying '-l=<1-9>'. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, false, "The path to the IPFS object(s) to be outputted.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, false, "The path to the IPFS object(s) to be outputted.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.StringOption("output", "o", "The path where the output should be stored."), - cmds.BoolOption("archive", "a", "Output a TAR archive.").Default(false), - cmds.BoolOption("compress", "C", "Compress the output with GZIP compression.").Default(false), - cmds.IntOption("compression-level", "l", "The level of compression (1-9).").Default(-1), + Options: []cmdkit.Option{ + cmdkit.StringOption("output", "o", "The path where the output should be stored."), + cmdkit.BoolOption("archive", "a", "Output a TAR archive.").Default(false), + cmdkit.BoolOption("compress", "C", "Compress the output with GZIP compression.").Default(false), + cmdkit.IntOption("compression-level", "l", "The level of compression (1-9).").Default(-1), }, PreRun: func(req cmds.Request) error { _, err := getCompressOptions(req) return err }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { if len(req.Arguments()) == 0 { - res.SetError(errors.New("not enough arugments provided"), cmds.ErrClient) + res.SetError(errors.New("not enough arugments provided"), cmdkit.ErrClient) return } - cmplvl, err := getCompressOptions(req) if err != nil { - res.SetError(err, cmds.ErrClient) + res.SetError(err, cmdkit.ErrNormal) return } node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } p := path.Path(req.Arguments()[0]) ctx := req.Context() dn, err := core.Resolve(ctx, node.Namesys, node.Resolver, p) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -79,7 +80,7 @@ may also specify the level of compression by specifying '-l=<1-9>'. case *dag.ProtoNode: size, err := dn.Size() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -87,51 +88,67 @@ may also specify the level of compression by specifying '-l=<1-9>'. case *dag.RawNode: res.SetLength(uint64(len(dn.RawData()))) default: - res.SetError(fmt.Errorf("'ipfs get' only supports unixfs nodes"), cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } archive, _, _ := req.Option("archive").Bool() reader, err := uarchive.DagArchive(ctx, dn, p.String(), node.DAG, archive, cmplvl) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(reader) + + res.Emit(reader) }, - PostRun: func(req cmds.Request, res cmds.Response) { - if res.Output() == nil { - return - } - outReader := res.Output().(io.Reader) - res.SetOutput(nil) + PostRun: map[cmds.EncodingType]func(cmds.Request, cmds.ResponseEmitter) cmds.ResponseEmitter{ + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter { + reNext, res := cmds.NewChanResponsePair(req) - outPath, _, _ := req.Option("output").String() - if len(outPath) == 0 { - _, outPath = gopath.Split(req.Arguments()[0]) - outPath = gopath.Clean(outPath) - } + go func() { + defer re.Close() - cmplvl, err := getCompressOptions(req) - if err != nil { - res.SetError(err, cmds.ErrClient) - return - } + v, err := res.Next() + if err != nil { + log.Error(e.New(err)) + return + } - archive, _, _ := req.Option("archive").Bool() + outReader, ok := v.(io.Reader) + if !ok { + log.Error(e.New(e.TypeErr(outReader, v))) + return + } - gw := getWriter{ - Out: os.Stdout, - Err: os.Stderr, - Archive: archive, - Compression: cmplvl, - Size: int64(res.Length()), - } + outPath, _, _ := req.Option("output").String() + if len(outPath) == 0 { + _, outPath = gopath.Split(req.Arguments()[0]) + outPath = gopath.Clean(outPath) + } - if err := gw.Write(outReader, outPath); err != nil { - res.SetError(err, cmds.ErrNormal) - return - } + cmplvl, err := getCompressOptions(req) + if err != nil { + re.SetError(err, cmdkit.ErrNormal) + return + } + + archive, _, _ := req.Option("archive").Bool() + + gw := getWriter{ + Out: os.Stdout, + Err: os.Stderr, + Archive: archive, + Compression: cmplvl, + Size: int64(res.Length()), + } + + if err := gw.Write(outReader, outPath); err != nil { + re.SetError(err, cmdkit.ErrNormal) + } + }() + + return reNext + }, }, } diff --git a/core/commands/helptext_test.go b/core/commands/helptext_test.go index d1acebe13..3b10b4702 100644 --- a/core/commands/helptext_test.go +++ b/core/commands/helptext_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - cmds "github.com/ipfs/go-ipfs/commands" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" ) func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) { diff --git a/core/commands/id.go b/core/commands/id.go index 05220cee9..96eecd8ff 100644 --- a/core/commands/id.go +++ b/core/commands/id.go @@ -8,14 +8,14 @@ import ( "io" "strings" - b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58" - cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - kb "gx/ipfs/QmSAFA8v42u4gpJNy1tb7vW3JiiXiaYDC2b845c2RnNSJL/go-libp2p-kbucket" + e "github.com/ipfs/go-ipfs/core/commands/e" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + kb "gx/ipfs/QmSAFA8v42u4gpJNy1tb7vW3JiiXiaYDC2b845c2RnNSJL/go-libp2p-kbucket" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58" "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" identify "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/protocol/identify" @@ -39,7 +39,7 @@ type IdOutput struct { } var IDCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Show ipfs node id info.", ShortDescription: ` Prints out information about the specified peer. @@ -57,16 +57,16 @@ EXAMPLE: ipfs id Qmece2RkXhsKe5CRooNisBTh4SK119KrXXGmoK6V3kb8aH -f="\n" `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("peerid", false, false, "Peer.ID of node to look up."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peerid", false, false, "Peer.ID of node to look up."), }, - Options: []cmds.Option{ - cmds.StringOption("format", "f", "Optional output format."), + Options: []cmdkit.Option{ + cmdkit.StringOption("format", "f", "Optional output format."), }, Run: func(req cmds.Request, res cmds.Response) { node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -74,7 +74,7 @@ EXAMPLE: if len(req.Arguments()) > 0 { id = peer.ID(b58.Decode(req.Arguments()[0])) if len(id) == 0 { - res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient) + res.SetError(cmds.ClientError("Invalid peer id"), cmdkit.ErrClient) return } } else { @@ -84,7 +84,7 @@ EXAMPLE: if id == node.Identity { output, err := printSelf(node) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(output) @@ -93,32 +93,37 @@ EXAMPLE: // TODO handle offline mode with polymorphism instead of conditionals if !node.OnlineMode() { - res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient) + res.SetError(errors.New(offlineIdErrorMessage), cmdkit.ErrClient) return } p, err := node.Routing.FindPeer(req.Context(), id) if err == kb.ErrLookupFailure { - res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient) + res.SetError(errors.New(offlineIdErrorMessage), cmdkit.ErrClient) return } if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } output, err := printPeer(node.Peerstore, p.ID) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(output) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - val, ok := res.Output().(*IdOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + val, ok := v.(*IdOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(val, v) } format, found, err := res.Request().Option("format").String() diff --git a/core/commands/ipns.go b/core/commands/ipns.go index 39e890a76..ce849b324 100644 --- a/core/commands/ipns.go +++ b/core/commands/ipns.go @@ -6,13 +6,15 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" namesys "github.com/ipfs/go-ipfs/namesys" offline "github.com/ipfs/go-ipfs/routing/offline" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var IpnsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Resolve IPNS names.", ShortDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and @@ -49,25 +51,25 @@ Resolve the value of a dnslink: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID."), }, - Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name.").Default(false), - cmds.BoolOption("nocache", "n", "Do not use cached entries.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name.").Default(false), + cmdkit.BoolOption("nocache", "n", "Do not use cached entries.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !n.OnlineMode() { err := n.SetupOfflineRouting() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -79,7 +81,7 @@ Resolve the value of a dnslink: var resolver namesys.Resolver = n.Namesys if local && nocache { - res.SetError(errors.New("cannot specify both local and nocache"), cmds.ErrNormal) + res.SetError(errors.New("cannot specify both local and nocache"), cmdkit.ErrNormal) return } @@ -95,7 +97,7 @@ Resolve the value of a dnslink: var name string if len(req.Arguments()) == 0 { if n.Identity == "" { - res.SetError(errors.New("identity not loaded"), cmds.ErrNormal) + res.SetError(errors.New("identity not loaded"), cmdkit.ErrNormal) return } name = n.Identity.Pretty() @@ -116,7 +118,7 @@ Resolve the value of a dnslink: output, err := resolver.ResolveN(req.Context(), name, depth) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -126,9 +128,14 @@ Resolve the value of a dnslink: }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - output, ok := res.Output().(*ResolvedPath) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + output, ok := v.(*ResolvedPath) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(output, v) } return strings.NewReader(output.Path.String() + "\n"), nil }, diff --git a/core/commands/keystore.go b/core/commands/keystore.go index 28a61c35e..7d3687277 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -3,7 +3,6 @@ package commands import ( "bytes" "crypto/rand" - "errors" "fmt" "io" "sort" @@ -11,13 +10,15 @@ import ( "text/tabwriter" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) var KeyCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Create and list IPNS name keypairs", ShortDescription: ` 'ipfs key gen' generates a new keypair for usage with IPNS and 'ipfs name @@ -59,43 +60,43 @@ type KeyRenameOutput struct { } var keyGenCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Create a new keypair", }, - Options: []cmds.Option{ - cmds.StringOption("type", "t", "type of the key to create [rsa, ed25519]"), - cmds.IntOption("size", "s", "size of the key to generate"), + Options: []cmdkit.Option{ + cmdkit.StringOption("type", "t", "type of the key to create [rsa, ed25519]"), + cmdkit.IntOption("size", "s", "size of the key to generate"), }, - Arguments: []cmds.Argument{ - cmds.StringArg("name", true, false, "name of key to create"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("name", true, false, "name of key to create"), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } typ, f, err := req.Option("type").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !f { - res.SetError(fmt.Errorf("please specify a key type with --type"), cmds.ErrNormal) + res.SetError(fmt.Errorf("please specify a key type with --type"), cmdkit.ErrNormal) return } size, sizefound, err := req.Option("size").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } name := req.Arguments()[0] if name == "self" { - res.SetError(fmt.Errorf("cannot create key with name 'self'"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot create key with name 'self'"), cmdkit.ErrNormal) return } @@ -105,13 +106,13 @@ var keyGenCmd = &cmds.Command{ switch typ { case "rsa": if !sizefound { - res.SetError(fmt.Errorf("please specify a key size with --size"), cmds.ErrNormal) + res.SetError(fmt.Errorf("please specify a key size with --size"), cmdkit.ErrNormal) return } priv, pub, err := ci.GenerateKeyPairWithReader(ci.RSA, size, rand.Reader) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -120,26 +121,26 @@ var keyGenCmd = &cmds.Command{ case "ed25519": priv, pub, err := ci.GenerateEd25519Key(rand.Reader) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } sk = priv pk = pub default: - res.SetError(fmt.Errorf("unrecognized key type: %s", typ), cmds.ErrNormal) + res.SetError(fmt.Errorf("unrecognized key type: %s", typ), cmdkit.ErrNormal) return } err = n.Repo.Keystore().Put(name, sk) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pid, err := peer.IDFromPublicKey(pk) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -150,9 +151,14 @@ var keyGenCmd = &cmds.Command{ }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - k, ok := res.Output().(*KeyOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + k, ok := v.(*KeyOutput) if !ok { - return nil, fmt.Errorf("expected a KeyOutput as command result") + return nil, e.TypeErr(k, v) } return strings.NewReader(k.Id + "\n"), nil @@ -162,22 +168,22 @@ var keyGenCmd = &cmds.Command{ } var keyListCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List all local keypairs", }, - Options: []cmds.Option{ - cmds.BoolOption("l", "Show extra information about keys."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("l", "Show extra information about keys."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } keys, err := n.Repo.Keystore().List() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -190,7 +196,7 @@ var keyListCmd = &cmds.Command{ for _, key := range keys { privKey, err := n.Repo.Keystore().Get(key) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -198,7 +204,7 @@ var keyListCmd = &cmds.Command{ pid, err := peer.IDFromPublicKey(pubKey) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -214,20 +220,20 @@ var keyListCmd = &cmds.Command{ } var keyRenameCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Rename a keypair", }, - Arguments: []cmds.Argument{ - cmds.StringArg("name", true, false, "name of key to rename"), - cmds.StringArg("newName", true, false, "new name of the key"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("name", true, false, "name of key to rename"), + cmdkit.StringArg("newName", true, false, "new name of the key"), }, - Options: []cmds.Option{ - cmds.BoolOption("force", "f", "Allow to overwrite an existing key."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("force", "f", "Allow to overwrite an existing key."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -237,18 +243,18 @@ var keyRenameCmd = &cmds.Command{ newName := req.Arguments()[1] if name == "self" { - res.SetError(fmt.Errorf("cannot rename key with name 'self'"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot rename key with name 'self'"), cmdkit.ErrNormal) return } if newName == "self" { - res.SetError(fmt.Errorf("cannot overwrite key with name 'self'"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot overwrite key with name 'self'"), cmdkit.ErrNormal) return } oldKey, err := ks.Get(name) if err != nil { - res.SetError(fmt.Errorf("no key named %s was found", name), cmds.ErrNormal) + res.SetError(fmt.Errorf("no key named %s was found", name), cmdkit.ErrNormal) return } @@ -256,7 +262,7 @@ var keyRenameCmd = &cmds.Command{ pid, err := peer.IDFromPublicKey(pubKey) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -265,7 +271,7 @@ var keyRenameCmd = &cmds.Command{ if force { exist, err := ks.Has(newName) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -273,7 +279,7 @@ var keyRenameCmd = &cmds.Command{ overwrite = true err := ks.Delete(newName) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -281,13 +287,13 @@ var keyRenameCmd = &cmds.Command{ err = ks.Put(newName, oldKey) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = ks.Delete(name) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -319,19 +325,19 @@ var keyRenameCmd = &cmds.Command{ } var keyRmCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove a keypair", }, - Arguments: []cmds.Argument{ - cmds.StringArg("name", true, true, "names of keys to remove").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("name", true, true, "names of keys to remove").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("l", "Show extra information about keys."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("l", "Show extra information about keys."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -340,13 +346,13 @@ var keyRmCmd = &cmds.Command{ list := make([]KeyOutput, 0, len(names)) for _, name := range names { if name == "self" { - res.SetError(fmt.Errorf("cannot remove key with name 'self'"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot remove key with name 'self'"), cmdkit.ErrNormal) return } removed, err := n.Repo.Keystore().Get(name) if err != nil { - res.SetError(fmt.Errorf("no key named %s was found", name), cmds.ErrNormal) + res.SetError(fmt.Errorf("no key named %s was found", name), cmdkit.ErrNormal) return } @@ -354,7 +360,7 @@ var keyRmCmd = &cmds.Command{ pid, err := peer.IDFromPublicKey(pubKey) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -364,7 +370,7 @@ var keyRmCmd = &cmds.Command{ for _, name := range names { err = n.Repo.Keystore().Delete(name) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -380,9 +386,13 @@ var keyRmCmd = &cmds.Command{ func keyOutputListMarshaler(res cmds.Response) (io.Reader, error) { withId, _, _ := res.Request().Option("l").Bool() - list, ok := res.Output().(*KeyOutputList) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + list, ok := v.(*KeyOutputList) if !ok { - return nil, errors.New("failed to cast []KeyOutput") + return nil, e.TypeErr(list, v) } buf := new(bytes.Buffer) diff --git a/core/commands/log.go b/core/commands/log.go index 9596cbb9f..38ef215de 100644 --- a/core/commands/log.go +++ b/core/commands/log.go @@ -4,9 +4,10 @@ import ( "fmt" "io" - logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" - cmds "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ) // Golang os.Args overrides * and replaces the character argument with @@ -16,7 +17,7 @@ import ( var logAllKeyword = "all" var LogCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with the daemon log output.", ShortDescription: ` 'ipfs log' contains utility commands to affect or read the logging @@ -32,7 +33,7 @@ output of a running daemon. } var logLevelCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Change the logging level.", ShortDescription: ` Change the verbosity of one or all subsystems log output. This does not affect @@ -40,11 +41,11 @@ the event log. `, }, - Arguments: []cmds.Argument{ + Arguments: []cmdkit.Argument{ // TODO use a different keyword for 'all' because all can theoretically // clash with a subsystem name - cmds.StringArg("subsystem", true, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)), - cmds.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'critical' the least verbose. + cmdkit.StringArg("subsystem", true, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)), + cmdkit.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'critical' the least verbose. One of: debug, info, warning, error, critical. `), }, @@ -58,7 +59,7 @@ the event log. } if err := logging.SetLogLevel(subsystem, level); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -73,7 +74,7 @@ the event log. } var logLsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List the logging subsystems.", ShortDescription: ` 'ipfs log ls' is a utility command used to list the logging @@ -90,7 +91,7 @@ subsystems of a running daemon. } var logTailCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Read the event log.", ShortDescription: ` Outputs event log messages (not other log messages) as they are generated. diff --git a/core/commands/ls.go b/core/commands/ls.go index 8c6bbb44d..91ad63222 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -9,6 +9,7 @@ import ( blockservice "github.com/ipfs/go-ipfs/blockservice" cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" offline "github.com/ipfs/go-ipfs/exchange/offline" merkledag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" @@ -17,6 +18,7 @@ import ( unixfspb "github.com/ipfs/go-ipfs/unixfs/pb" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type LsLink struct { @@ -35,7 +37,7 @@ type LsOutput struct { } var LsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List directory contents for Unix filesystem objects.", ShortDescription: ` Displays the contents of an IPFS or IPNS object(s) at the given path, with @@ -47,29 +49,29 @@ The JSON output contains type information. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false), - cmds.BoolOption("resolve-type", "Resolve linked objects to find out their types.").Default(true), + Options: []cmdkit.Option{ + cmdkit.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false), + cmdkit.BoolOption("resolve-type", "Resolve linked objects to find out their types.").Default(true), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // get options early -> exit early in case of error if _, _, err := req.Option("headers").Bool(); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } resolve, _, err := req.Option("resolve-type").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -86,7 +88,7 @@ The JSON output contains type information. for _, fpath := range paths { p, err := path.ParsePath(fpath) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -97,17 +99,18 @@ The JSON output contains type information. dagnode, err := core.Resolve(req.Context(), nd.Namesys, r, p) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dagnodes = append(dagnodes, dagnode) } output := make([]LsObject, len(req.Arguments())) + for i, dagnode := range dagnodes { dir, err := uio.NewDirectoryFromNode(nd.DAG, dagnode) if err != nil && err != uio.ErrNotADir { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -117,7 +120,7 @@ The JSON output contains type information. } else { links, err = dir.Links(req.Context()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -135,14 +138,14 @@ The JSON output contains type information. // not an error linkNode = nil } else if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if pn, ok := linkNode.(*merkledag.ProtoNode); ok { d, err := unixfs.FromBytes(pn.Data()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -162,8 +165,17 @@ The JSON output contains type information. Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + headers, _, _ := res.Request().Option("headers").Bool() - output := res.Output().(*LsOutput) + output, ok := v.(*LsOutput) + if !ok { + return nil, e.TypeErr(output, v) + } + buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0) for _, object := range output.Objects { diff --git a/core/commands/mount_nofuse.go b/core/commands/mount_nofuse.go index 07ab82e6d..e2e8c932d 100644 --- a/core/commands/mount_nofuse.go +++ b/core/commands/mount_nofuse.go @@ -5,10 +5,12 @@ package commands import ( cmds "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var MountCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Mounts ipfs to the filesystem (disabled).", ShortDescription: ` This version of ipfs is compiled without fuse support, which is required diff --git a/core/commands/mount_unix.go b/core/commands/mount_unix.go index 8661c62c0..126500845 100644 --- a/core/commands/mount_unix.go +++ b/core/commands/mount_unix.go @@ -9,12 +9,15 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" nodeMount "github.com/ipfs/go-ipfs/fuse/node" config "github.com/ipfs/go-ipfs/repo/config" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var MountCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Mounts IPFS to the filesystem (read-only).", ShortDescription: ` Mount IPFS at a read-only mountpoint on the OS (default: /ipfs and /ipns). @@ -70,32 +73,32 @@ baz baz `, }, - Options: []cmds.Option{ - cmds.StringOption("ipfs-path", "f", "The path where IPFS should be mounted."), - cmds.StringOption("ipns-path", "n", "The path where IPNS should be mounted."), + Options: []cmdkit.Option{ + cmdkit.StringOption("ipfs-path", "f", "The path where IPFS should be mounted."), + cmdkit.StringOption("ipns-path", "n", "The path where IPNS should be mounted."), }, Run: func(req cmds.Request, res cmds.Response) { cfg, err := req.InvocContext().GetConfig() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // error if we aren't running node in online mode if node.LocalMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } fsdir, found, err := req.Option("f").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !found { @@ -105,7 +108,7 @@ baz // get default mount points nsdir, found, err := req.Option("n").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !found { @@ -114,7 +117,7 @@ baz err = nodeMount.Mount(node, fsdir, nsdir) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -126,9 +129,18 @@ baz Type: config.Mounts{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v := res.Output().(*config.Mounts) - s := fmt.Sprintf("IPFS mounted at: %s\n", v.IPFS) - s += fmt.Sprintf("IPNS mounted at: %s\n", v.IPNS) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + mnts, ok := v.(*config.Mounts) + if !ok { + return nil, e.TypeErr(mnts, v) + } + + s := fmt.Sprintf("IPFS mounted at: %s\n", mnts.IPFS) + s += fmt.Sprintf("IPNS mounted at: %s\n", mnts.IPNS) return strings.NewReader(s), nil }, }, diff --git a/core/commands/mount_windows.go b/core/commands/mount_windows.go index 8eeb6bfbb..20c6cf0e7 100644 --- a/core/commands/mount_windows.go +++ b/core/commands/mount_windows.go @@ -3,16 +3,18 @@ package commands import ( "errors" + "gx/ipfs/QmadYQbq2fJpaRE3XhpMLH68NNxmWMwfMQy1ntr1cKf7eo/go-ipfs-cmdkit" + cmds "github.com/ipfs/go-ipfs/commands" ) var MountCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Not yet implemented on Windows.", ShortDescription: "Not yet implemented on Windows. :(", }, Run: func(req cmds.Request, res cmds.Response) { - res.SetError(errors.New("Mount isn't compatible with Windows yet"), cmds.ErrNormal) + res.SetError(errors.New("Mount isn't compatible with Windows yet"), cmdkit.ErrNormal) }, } diff --git a/core/commands/name.go b/core/commands/name.go index 5288e5c08..61cde2482 100644 --- a/core/commands/name.go +++ b/core/commands/name.go @@ -1,6 +1,10 @@ package commands -import cmds "github.com/ipfs/go-ipfs/commands" +import ( + cmds "github.com/ipfs/go-ipfs/commands" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" +) type IpnsEntry struct { Name string @@ -8,7 +12,7 @@ type IpnsEntry struct { } var NameCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Publish and resolve IPNS names.", ShortDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and diff --git a/core/commands/object/diff.go b/core/commands/object/diff.go index 949138c21..ad3b0d4ff 100644 --- a/core/commands/object/diff.go +++ b/core/commands/object/diff.go @@ -7,8 +7,10 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" dagutils "github.com/ipfs/go-ipfs/merkledag/utils" path "github.com/ipfs/go-ipfs/path" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type Changes struct { @@ -16,7 +18,7 @@ type Changes struct { } var ObjectDiffCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Display the diff between two ipfs objects.", ShortDescription: ` 'ipfs object diff' is a command used to show the differences between @@ -42,17 +44,17 @@ Example: Changed "bar" from QmNgd5cz2jNftnAHBhcRUGdtiaMzb5Rhjqd4etondHHST8 to QmRfFVsjSXkhFxrfWnLpMae2M4GBVsry6VAuYYcji5MiZb. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("obj_a", true, false, "Object to diff against."), - cmds.StringArg("obj_b", true, false, "Object to diff."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("obj_a", true, false, "Object to diff against."), + cmdkit.StringArg("obj_b", true, false, "Object to diff."), }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "Print extra information."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "Print extra information."), }, Run: func(req cmds.Request, res cmds.Response) { node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -61,13 +63,13 @@ Example: pa, err := path.ParsePath(a) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pb, err := path.ParsePath(b) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -75,19 +77,19 @@ Example: obj_a, err := core.Resolve(ctx, node.Namesys, node.Resolver, pa) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } obj_b, err := core.Resolve(ctx, node.Namesys, node.Resolver, pb) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } changes, err := dagutils.Diff(ctx, node.DAG, obj_a, obj_b) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -96,8 +98,17 @@ Example: Type: Changes{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + verbose, _, _ := res.Request().Option("v").Bool() - changes := res.Output().(*Changes) + changes, ok := v.(*Changes) + if !ok { + return nil, e.TypeErr(changes, v) + } + buf := new(bytes.Buffer) for _, change := range changes.Changes { if verbose { diff --git a/core/commands/object/object.go b/core/commands/object/object.go index c10567189..5c902aa29 100644 --- a/core/commands/object/object.go +++ b/core/commands/object/object.go @@ -14,10 +14,12 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" pin "github.com/ipfs/go-ipfs/pin" ft "github.com/ipfs/go-ipfs/unixfs" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" @@ -44,7 +46,7 @@ type Object struct { } var ObjectCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with IPFS objects.", ShortDescription: ` 'ipfs object' is a plumbing command used to manipulate DAG objects @@ -64,7 +66,7 @@ directly.`, } var ObjectDataCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Output the raw bytes of an IPFS object.", ShortDescription: ` 'ipfs object data' is a plumbing command for retrieving the raw bytes stored @@ -79,31 +81,31 @@ is the raw data of the object. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fpath, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pbnode, ok := node.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } @@ -112,7 +114,7 @@ is the raw data of the object. } var ObjectLinksCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Output the links pointed to by the specified object.", ShortDescription: ` 'ipfs object links' is a plumbing command for retrieving the links from @@ -121,42 +123,51 @@ multihash. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // get options early -> exit early in case of error if _, _, err := req.Option("headers").Bool(); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fpath := path.Path(req.Arguments()[0]) node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } output, err := getOutput(node) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(output) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - object := res.Output().(*Object) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + object, ok := v.(*Object) + if !ok { + return nil, e.TypeErr(object, v) + } + buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0) headers, _, _ := res.Request().Option("headers").Bool() @@ -174,7 +185,7 @@ multihash. } var ObjectGetCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Get and serialize the DAG node named by .", ShortDescription: ` 'ipfs object get' is a plumbing command for retrieving DAG nodes. @@ -193,13 +204,13 @@ This command outputs data in the following encodings: (Specified by the "--encoding" or "--enc" flag)`, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -207,13 +218,13 @@ This command outputs data in the following encodings: object, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pbo, ok := object.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } @@ -235,7 +246,16 @@ This command outputs data in the following encodings: Type: Node{}, Marshalers: cmds.MarshalerMap{ cmds.Protobuf: func(res cmds.Response) (io.Reader, error) { - node := res.Output().(*Node) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + node, ok := v.(*Node) + if !ok { + return nil, e.TypeErr(node, v) + } + // deserialize the Data field as text as this was the standard behaviour object, err := deserializeNode(node, "text") if err != nil { @@ -252,7 +272,7 @@ This command outputs data in the following encodings: } var ObjectStatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Get stats for the DAG node named by .", ShortDescription: ` 'ipfs object stat' is a plumbing command to print DAG node statistics. @@ -266,13 +286,13 @@ var ObjectStatCmd = &cmds.Command{ `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -280,13 +300,13 @@ var ObjectStatCmd = &cmds.Command{ object, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, fpath) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } ns, err := object.Stat() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -295,7 +315,15 @@ var ObjectStatCmd = &cmds.Command{ Type: node.NodeStat{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - ns := res.Output().(*node.NodeStat) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + ns, ok := v.(*node.NodeStat) + if !ok { + return nil, e.TypeErr(ns, v) + } buf := new(bytes.Buffer) w := func(s string, n int) { @@ -313,7 +341,7 @@ var ObjectStatCmd = &cmds.Command{ } var ObjectPutCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Store input as a DAG object, print its key.", ShortDescription: ` 'ipfs object put' is a plumbing command for storing DAG nodes. @@ -350,42 +378,42 @@ And then run: `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("data", true, false, "Data to be stored as a DAG object.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("data", true, false, "Data to be stored as a DAG object.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.StringOption("inputenc", "Encoding type of input data. One of: {\"protobuf\", \"json\"}.").Default("json"), - cmds.StringOption("datafieldenc", "Encoding type of the data field, either \"text\" or \"base64\".").Default("text"), - cmds.BoolOption("pin", "Pin this object when adding.").Default(false), + Options: []cmdkit.Option{ + cmdkit.StringOption("inputenc", "Encoding type of input data. One of: {\"protobuf\", \"json\"}.").Default("json"), + cmdkit.StringOption("datafieldenc", "Encoding type of the data field, either \"text\" or \"base64\".").Default("text"), + cmdkit.BoolOption("pin", "Pin this object when adding.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } input, err := req.Files().NextFile() if err != nil && err != io.EOF { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } inputenc, _, err := req.Option("inputenc").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } datafieldenc, _, err := req.Option("datafieldenc").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } dopin, _, err := req.Option("pin").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -395,9 +423,9 @@ And then run: objectCid, err := objectPut(n, input, inputenc, datafieldenc) if err != nil { - errType := cmds.ErrNormal + errType := cmdkit.ErrNormal if err == ErrUnknownObjectEnc { - errType = cmds.ErrClient + errType = cmdkit.ErrClient } res.SetError(err, errType) return @@ -407,7 +435,7 @@ And then run: n.Pinning.PinWithMode(objectCid, pin.Recursive) err = n.Pinning.Flush() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -416,15 +444,23 @@ And then run: }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - object := res.Output().(*Object) - return strings.NewReader("added " + object.Hash + "\n"), nil + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + obj, ok := v.(*Object) + if !ok { + return nil, e.TypeErr(obj, v) + } + + return strings.NewReader("added " + obj.Hash + "\n"), nil }, }, Type: Object{}, } var ObjectNewCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Create a new object from an ipfs template.", ShortDescription: ` 'ipfs object new' is a plumbing command for creating new DAG nodes. @@ -439,13 +475,13 @@ Available templates: * unixfs-dir `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("template", false, false, "Template to use. Optional."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("template", false, false, "Template to use. Optional."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -455,22 +491,31 @@ Available templates: var err error node, err = nodeFromTemplate(template) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } k, err := n.DAG.Add(node) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&Object{Hash: k.String()}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - object := res.Output().(*Object) - return strings.NewReader(object.Hash + "\n"), nil + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + obj, ok := v.(*Object) + if !ok { + return nil, e.TypeErr(obj, v) + } + + return strings.NewReader(obj.Hash + "\n"), nil }, }, Type: Object{}, @@ -628,3 +673,17 @@ func deserializeNode(nd *Node, dataFieldEncoding string) (*dag.ProtoNode, error) func NodeEmpty(node *Node) bool { return (node.Data == "" && len(node.Links) == 0) } + +// copy+pasted from ../commands.go +func unwrapOutput(i interface{}) (interface{}, error) { + var ( + ch <-chan interface{} + ok bool + ) + + if ch, ok = i.(<-chan interface{}); !ok { + return nil, e.TypeErr(ch, i) + } + + return <-ch, nil +} diff --git a/core/commands/object/patch.go b/core/commands/object/patch.go index 093457270..a2c09c83b 100644 --- a/core/commands/object/patch.go +++ b/core/commands/object/patch.go @@ -7,15 +7,17 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" dag "github.com/ipfs/go-ipfs/merkledag" dagutils "github.com/ipfs/go-ipfs/merkledag/utils" path "github.com/ipfs/go-ipfs/path" ft "github.com/ipfs/go-ipfs/unixfs" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var ObjectPatchCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Create a new merkledag object based on an existing one.", ShortDescription: ` 'ipfs object patch ' is a plumbing command used to @@ -23,7 +25,7 @@ build custom DAG objects. It mutates objects, creating new objects as a result. This is the Merkle-DAG version of modifying an object. `, }, - Arguments: []cmds.Argument{}, + Arguments: []cmdkit.Argument{}, Subcommands: map[string]*cmds.Command{ "append-data": patchAppendDataCmd, "add-link": patchAddLinkCmd, @@ -33,16 +35,21 @@ result. This is the Merkle-DAG version of modifying an object. } func objectMarshaler(res cmds.Response) (io.Reader, error) { - o, ok := res.Output().(*Object) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + o, ok := v.(*Object) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(o, v) } return strings.NewReader(o.Hash + "\n"), nil } var patchAppendDataCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Append data to the data segment of a dag node.", ShortDescription: ` Append data to what already exists in the data segment in the given object. @@ -56,44 +63,44 @@ data within an object. Objects have a max size of 1MB and objects larger than the limit will not be respected by the network. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("root", true, false, "The hash of the node to modify."), - cmds.FileArg("data", true, false, "Data to append.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("root", true, false, "The hash of the node to modify."), + cmdkit.FileArg("data", true, false, "Data to append.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } root, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rootnd, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, root) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rtpb, ok := rootnd.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } fi, err := req.Files().NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } data, err := ioutil.ReadAll(fi) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -101,7 +108,7 @@ the limit will not be respected by the network. newkey, err := nd.DAG.Add(rtpb) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -114,7 +121,7 @@ the limit will not be respected by the network. } var patchSetDataCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Set the data field of an IPFS object.", ShortDescription: ` Set the data of an IPFS object from stdin or with the contents of a file. @@ -124,44 +131,44 @@ Example: $ echo "my data" | ipfs object patch $MYHASH set-data `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("root", true, false, "The hash of the node to modify."), - cmds.FileArg("data", true, false, "The data to set the object to.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("root", true, false, "The hash of the node to modify."), + cmdkit.FileArg("data", true, false, "The data to set the object to.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rp, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rp) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rtpb, ok := root.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } fi, err := req.Files().NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } data, err := ioutil.ReadAll(fi) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -169,7 +176,7 @@ Example: newkey, err := nd.DAG.Add(rtpb) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -182,38 +189,38 @@ Example: } var patchRmLinkCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove a link from an object.", ShortDescription: ` Removes a link by the given name from root. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("root", true, false, "The hash of the node to modify."), - cmds.StringArg("link", true, false, "Name of the link to remove."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("root", true, false, "The hash of the node to modify."), + cmdkit.StringArg("link", true, false, "Name of the link to remove."), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rootp, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rootp) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rtpb, ok := root.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } @@ -223,13 +230,13 @@ Removes a link by the given name from root. err = e.RmLink(req.Context(), path) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } nnode, err := e.Finalize(nd.DAG) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -244,7 +251,7 @@ Removes a link by the given name from root. } var patchAddLinkCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Add a link to a given object.", ShortDescription: ` Add a Merkle-link to the given object and return the hash of the result. @@ -259,49 +266,49 @@ This takes an empty directory, and adds a link named 'foo' under it, pointing to a file containing 'bar', and returns the hash of the new object. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("root", true, false, "The hash of the node to modify."), - cmds.StringArg("name", true, false, "Name of link to create."), - cmds.StringArg("ref", true, false, "IPFS object to add link to."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("root", true, false, "The hash of the node to modify."), + cmdkit.StringArg("name", true, false, "Name of link to create."), + cmdkit.StringArg("ref", true, false, "IPFS object to add link to."), }, - Options: []cmds.Option{ - cmds.BoolOption("create", "p", "Create intermediary nodes.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("create", "p", "Create intermediary nodes.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rootp, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, rootp) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rtpb, ok := root.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } npath := req.Arguments()[1] childp, err := path.ParsePath(req.Arguments()[2]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } create, _, err := req.Option("create").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -314,25 +321,25 @@ to a file containing 'bar', and returns the hash of the new object. childnd, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, childp) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } chpb, ok := childnd.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } err = e.InsertNodeAtPath(req.Context(), npath, chpb, createfunc) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } nnode, err := e.Finalize(nd.DAG) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } diff --git a/core/commands/p2p.go b/core/commands/p2p.go index 83503400c..a6c84950f 100644 --- a/core/commands/p2p.go +++ b/core/commands/p2p.go @@ -11,6 +11,7 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" ) @@ -42,7 +43,7 @@ type P2PStreamsOutput struct { // P2PCmd is the 'ipfs p2p' command var P2PCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Libp2p stream mounting.", ShortDescription: ` Create and use tunnels to remote peers over libp2p @@ -59,7 +60,7 @@ are refined`, // p2pListenerCmd is the 'ipfs p2p listener' command var p2pListenerCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "P2P listener management.", ShortDescription: "Create and manage listener p2p endpoints", }, @@ -73,7 +74,7 @@ var p2pListenerCmd = &cmds.Command{ // p2pStreamCmd is the 'ipfs p2p stream' command var p2pStreamCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "P2P stream management.", ShortDescription: "Create and manage p2p streams", }, @@ -86,17 +87,17 @@ var p2pStreamCmd = &cmds.Command{ } var p2pListenerLsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List active p2p listeners.", }, - Options: []cmds.Option{ - cmds.BoolOption("headers", "v", "Print table headers (HandlerID, Protocol, Local, Remote).").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("headers", "v", "Print table headers (HandlerID, Protocol, Local, Remote).").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := getNode(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -114,8 +115,13 @@ var p2pListenerLsCmd = &cmds.Command{ Type: P2PLsOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + headers, _, _ := res.Request().Option("headers").Bool() - list, _ := res.Output().(*P2PLsOutput) + list := v.(*P2PLsOutput) buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0) for _, listener := range list.Listeners { @@ -133,16 +139,16 @@ var p2pListenerLsCmd = &cmds.Command{ } var p2pStreamLsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List active p2p streams.", }, - Options: []cmds.Option{ - cmds.BoolOption("headers", "v", "Print table headers (HagndlerID, Protocol, Local, Remote).").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("headers", "v", "Print table headers (HagndlerID, Protocol, Local, Remote).").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := getNode(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -167,8 +173,13 @@ var p2pStreamLsCmd = &cmds.Command{ Type: P2PStreamsOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + headers, _, _ := res.Request().Option("headers").Bool() - list, _ := res.Output().(*P2PStreamsOutput) + list := v.(*P2PStreamsOutput) buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0) for _, stream := range list.Streams { @@ -186,7 +197,7 @@ var p2pStreamLsCmd = &cmds.Command{ } var p2pListenerListenCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Forward p2p connections to a network multiaddr.", ShortDescription: ` Register a p2p connection handler and forward the connections to a specified @@ -195,32 +206,32 @@ address. Note that the connections originate from the ipfs daemon process. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("Protocol", true, false, "Protocol identifier."), - cmds.StringArg("Address", true, false, "Request handling application address."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("Protocol", true, false, "Protocol identifier."), + cmdkit.StringArg("Address", true, false, "Request handling application address."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := getNode(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } proto := "/p2p/" + req.Arguments()[0] if n.P2P.CheckProtoExists(proto) { - res.SetError(errors.New("protocol handler already registered"), cmds.ErrNormal) + res.SetError(errors.New("protocol handler already registered"), cmdkit.ErrNormal) return } addr, err := ma.NewMultiaddr(req.Arguments()[1]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } _, err = n.P2P.NewListener(n.Context(), proto, addr) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -233,7 +244,7 @@ Note that the connections originate from the ipfs daemon process. } var p2pStreamDialCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Dial to a p2p listener.", ShortDescription: ` @@ -244,21 +255,21 @@ time TCP listener and return it's bind port, this way a dialing application can transparently connect to a p2p service. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("Peer", true, false, "Remote peer to connect to"), - cmds.StringArg("Protocol", true, false, "Protocol identifier."), - cmds.StringArg("BindAddress", false, false, "Address to listen for connection/s (default: /ip4/127.0.0.1/tcp/0)."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("Peer", true, false, "Remote peer to connect to"), + cmdkit.StringArg("Protocol", true, false, "Protocol identifier."), + cmdkit.StringArg("BindAddress", false, false, "Address to listen for connection/s (default: /ip4/127.0.0.1/tcp/0)."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := getNode(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } addr, peer, err := ParsePeerParam(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -268,14 +279,14 @@ can transparently connect to a p2p service. if len(req.Arguments()) == 3 { bindAddr, err = ma.NewMultiaddr(req.Arguments()[2]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } listenerInfo, err := n.P2P.Dial(n.Context(), addr, peer, proto, bindAddr) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -289,19 +300,21 @@ can transparently connect to a p2p service. } var p2pListenerCloseCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Close active p2p listener.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("Protocol", false, false, "P2P listener protocol"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("Protocol", false, false, "P2P listener protocol"), }, - Options: []cmds.Option{ - cmds.BoolOption("all", "a", "Close all listeners.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("all", "a", "Close all listeners.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { + res.SetOutput(nil) + n, err := getNode(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -310,7 +323,7 @@ var p2pListenerCloseCmd = &cmds.Command{ if !closeAll { if len(req.Arguments()) == 0 { - res.SetError(errors.New("no protocol name specified"), cmds.ErrNormal) + res.SetError(errors.New("no protocol name specified"), cmdkit.ErrNormal) return } @@ -330,19 +343,21 @@ var p2pListenerCloseCmd = &cmds.Command{ } var p2pStreamCloseCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Close active p2p stream.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("HandlerID", false, false, "Stream HandlerID"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("HandlerID", false, false, "Stream HandlerID"), }, - Options: []cmds.Option{ - cmds.BoolOption("all", "a", "Close all streams.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("all", "a", "Close all streams.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { + res.SetOutput(nil) + n, err := getNode(req) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -351,13 +366,13 @@ var p2pStreamCloseCmd = &cmds.Command{ if !closeAll { if len(req.Arguments()) == 0 { - res.SetError(errors.New("no HandlerID specified"), cmds.ErrNormal) + res.SetError(errors.New("no HandlerID specified"), cmdkit.ErrNormal) return } handlerID, err = strconv.ParseUint(req.Arguments()[0], 10, 64) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } diff --git a/core/commands/pin.go b/core/commands/pin.go index af2bca24a..8b23ad6bb 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -2,25 +2,27 @@ package commands import ( "bytes" + "context" "fmt" "io" "time" cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" corerepo "github.com/ipfs/go-ipfs/core/corerepo" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" pin "github.com/ipfs/go-ipfs/pin" uio "github.com/ipfs/go-ipfs/unixfs/io" - context "context" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" ) var PinCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Pin (and unpin) objects to local storage.", }, @@ -43,23 +45,23 @@ type AddPinOutput struct { } var addPinCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Pin objects to local storage.", ShortDescription: "Stores an IPFS object(s) from a given path locally to disk.", }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s).").Default(true), - cmds.BoolOption("progress", "Show progress"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s).").Default(true), + cmdkit.BoolOption("progress", "Show progress"), }, Type: AddPinOutput{}, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -68,7 +70,7 @@ var addPinCmd = &cmds.Command{ // set recursive flag recursive, _, err := req.Option("recursive").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } showProgress, _, _ := req.Option("progress").Bool() @@ -76,13 +78,15 @@ var addPinCmd = &cmds.Command{ if !showProgress { added, err := corerepo.Pin(n, req.Context(), req.Arguments(), recursive) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&AddPinOutput{Pins: cidsToStrings(added)}) return } + out := make(chan interface{}) + res.SetOutput((<-chan interface{})(out)) v := new(dag.ProgressTracker) ctx := v.DeriveContext(req.Context()) @@ -91,68 +95,62 @@ var addPinCmd = &cmds.Command{ defer close(ch) added, err := corerepo.Pin(n, ctx, req.Arguments(), recursive) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } ch <- added }() - out := make(chan interface{}) - res.SetOutput((<-chan interface{})(out)) - go func() { - ticker := time.NewTicker(500 * time.Millisecond) - defer ticker.Stop() - defer close(out) - for { - select { - case val, ok := <-ch: - if !ok { - // error already set just return - return - } - if pv := v.Value(); pv != 0 { - out <- &AddPinOutput{Progress: v.Value()} - } - out <- &AddPinOutput{Pins: cidsToStrings(val)} - return - case <-ticker.C: - out <- &AddPinOutput{Progress: v.Value()} - case <-ctx.Done(): - res.SetError(ctx.Err(), cmds.ErrNormal) + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + defer close(out) + for { + select { + case val, ok := <-ch: + if !ok { + // error already set just return return } + + if pv := v.Value(); pv != 0 { + out <- &AddPinOutput{Progress: v.Value()} + } + out <- &AddPinOutput{Pins: cidsToStrings(val)} + return + case <-ticker.C: + out <- &AddPinOutput{Progress: v.Value()} + case <-ctx.Done(): + log.Error(ctx.Err()) + res.SetError(ctx.Err(), cmdkit.ErrNormal) + return } - }() + } }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + var added []string - switch out := res.Output().(type) { + switch out := v.(type) { case *AddPinOutput: - added = out.Pins - case <-chan interface{}: - progressLine := false - for r0 := range out { - r := r0.(*AddPinOutput) - if r.Pins != nil { - added = r.Pins - } else { - if progressLine { - fmt.Fprintf(res.Stderr(), "\r") - } - fmt.Fprintf(res.Stderr(), "Fetched/Processed %d nodes", r.Progress) - progressLine = true - } - } - if progressLine { - fmt.Fprintf(res.Stderr(), "\n") + if out.Pins != nil { + added = out.Pins + } else { + // this can only happen if the progress option is set + fmt.Fprintf(res.Stderr(), "Fetched/Processed %d nodes\r", out.Progress) } + if res.Error() != nil { return nil, res.Error() } default: - return nil, u.ErrCast() + return nil, e.TypeErr(out, v) } + var pintype string rec, found, _ := res.Request().Option("recursive").Bool() if rec || !found { @@ -171,7 +169,7 @@ var addPinCmd = &cmds.Command{ } var rmPinCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove pinned objects from local storage.", ShortDescription: ` Removes the pin from the given object allowing it to be garbage @@ -179,30 +177,30 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.) `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s).").Default(true), + Options: []cmdkit.Option{ + cmdkit.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s).").Default(true), }, Type: PinOutput{}, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // set recursive flag recursive, _, err := req.Option("recursive").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } removed, err := corerepo.Unpin(n, req.Context(), req.Arguments(), recursive) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -210,9 +208,14 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - added, ok := res.Output().(*PinOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + added, ok := v.(*PinOutput) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(added, v) } buf := new(bytes.Buffer) @@ -225,7 +228,7 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.) } var listPinCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List objects pinned to local storage.", ShortDescription: ` Returns a list of objects that are pinned locally. @@ -268,23 +271,23 @@ Example: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", false, true, "Path to object(s) to be listed."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", false, true, "Path to object(s) to be listed."), }, - Options: []cmds.Option{ - cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").Default("all"), - cmds.BoolOption("quiet", "q", "Write just hashes of objects.").Default(false), + Options: []cmdkit.Option{ + cmdkit.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").Default("all"), + cmdkit.BoolOption("quiet", "q", "Write just hashes of objects.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } typeStr, _, err := req.Option("type").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -292,7 +295,7 @@ Example: case "all", "direct", "indirect", "recursive": default: err = fmt.Errorf("Invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr) - res.SetError(err, cmds.ErrClient) + res.SetError(err, cmdkit.ErrClient) return } @@ -305,7 +308,7 @@ Example: } if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) } else { res.SetOutput(&RefKeyList{Keys: keys}) } @@ -313,14 +316,19 @@ Example: Type: RefKeyList{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + quiet, _, err := res.Request().Option("quiet").Bool() if err != nil { return nil, err } - keys, ok := res.Output().(*RefKeyList) + keys, ok := v.(*RefKeyList) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(keys, v) } out := new(bytes.Buffer) for k, v := range keys.Keys { @@ -336,7 +344,7 @@ Example: } var updatePinCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Update a recursive pin", ShortDescription: ` Updates one pin to another, making sure that all objects in the new pin are @@ -345,36 +353,36 @@ new pin and removing the old one. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("from-path", true, false, "Path to old object."), - cmds.StringArg("to-path", true, false, "Path to new object to be pinned."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("from-path", true, false, "Path to old object."), + cmdkit.StringArg("to-path", true, false, "Path to new object to be pinned."), }, - Options: []cmds.Option{ - cmds.BoolOption("unpin", "Remove the old pin.").Default(true), + Options: []cmdkit.Option{ + cmdkit.BoolOption("unpin", "Remove the old pin.").Default(true), }, Type: PinOutput{}, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } unpin, _, err := req.Option("unpin").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } from, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } to, err := path.ParsePath(req.Arguments()[1]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -385,19 +393,19 @@ new pin and removing the old one. fromc, err := core.ResolveToCid(req.Context(), n.Namesys, r, from) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } toc, err := core.ResolveToCid(req.Context(), n.Namesys, r, to) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = n.Pinning.Update(req.Context(), fromc, toc, unpin) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -418,17 +426,17 @@ new pin and removing the old one. } var verifyPinCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Verify that recursive pins are complete.", }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "Also write the hashes of non-broken pins."), - cmds.BoolOption("quiet", "q", "Write just hashes of broken pins."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "Also write the hashes of non-broken pins."), + cmdkit.BoolOption("quiet", "q", "Write just hashes of broken pins."), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -436,7 +444,7 @@ var verifyPinCmd = &cmds.Command{ quiet, _, _ := res.Request().Option("quiet").Bool() if verbose && quiet { - res.SetError(fmt.Errorf("The --verbose and --quiet options can not be used at the same time"), cmds.ErrNormal) + res.SetError(fmt.Errorf("The --verbose and --quiet options can not be used at the same time"), cmdkit.ErrNormal) } opts := pinVerifyOpts{ diff --git a/core/commands/ping.go b/core/commands/ping.go index e98b09088..e37ed324c 100644 --- a/core/commands/ping.go +++ b/core/commands/ping.go @@ -2,20 +2,20 @@ package commands import ( "bytes" + "context" "fmt" "io" - "reflect" "strings" "time" cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" - peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" - context "context" + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" + peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ) const kPingTimeout = 10 * time.Second @@ -27,7 +27,7 @@ type PingResult struct { } var PingCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Send echo request packets to IPFS hosts.", ShortDescription: ` 'ipfs ping' is a tool to test sending data to other nodes. It finds nodes @@ -35,61 +35,52 @@ via the routing system, sends pings, waits for pongs, and prints out round- trip latency information. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("peer ID", true, true, "ID of peer to be pinged.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("peer ID", true, true, "ID of peer to be pinged.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.IntOption("count", "n", "Number of ping messages to send.").Default(10), + Options: []cmdkit.Option{ + cmdkit.IntOption("count", "n", "Number of ping messages to send.").Default(10), }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + obj, ok := v.(*PingResult) if !ok { - fmt.Println(reflect.TypeOf(res.Output())) return nil, u.ErrCast() } - marshal := func(v interface{}) (io.Reader, error) { - obj, ok := v.(*PingResult) - if !ok { - return nil, u.ErrCast() - } - - buf := new(bytes.Buffer) - if len(obj.Text) > 0 { - buf = bytes.NewBufferString(obj.Text + "\n") - } else if obj.Success { - fmt.Fprintf(buf, "Pong received: time=%.2f ms\n", obj.Time.Seconds()*1000) - } else { - fmt.Fprintf(buf, "Pong failed\n") - } - return buf, nil + buf := new(bytes.Buffer) + if len(obj.Text) > 0 { + buf = bytes.NewBufferString(obj.Text + "\n") + } else if obj.Success { + fmt.Fprintf(buf, "Pong received: time=%.2f ms\n", obj.Time.Seconds()*1000) + } else { + fmt.Fprintf(buf, "Pong failed\n") } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil + return buf, nil }, }, Run: func(req cmds.Request, res cmds.Response) { ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // Must be online! if !n.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } addr, peerID, err := ParsePeerParam(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -99,7 +90,7 @@ trip latency information. numPings, _, err := req.Option("count").Int() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -140,7 +131,6 @@ func pingPeer(ctx context.Context, n *core.IpfsNode, pid peer.ID, numPings int) defer cancel() pings, err := n.Ping.Ping(ctx, pid) if err != nil { - log.Debugf("Ping error: %s", err) outChan <- &PingResult{ Success: false, Text: fmt.Sprintf("Ping error: %s", err), diff --git a/core/commands/publish.go b/core/commands/publish.go index c3a28b191..9a9f94b97 100644 --- a/core/commands/publish.go +++ b/core/commands/publish.go @@ -10,9 +10,11 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" keystore "github.com/ipfs/go-ipfs/keystore" path "github.com/ipfs/go-ipfs/path" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" crypto "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) @@ -20,7 +22,7 @@ import ( var errNotOnline = errors.New("This command must be run in online mode. Try running 'ipfs daemon' first.") var PublishCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Publish IPNS names.", ShortDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and @@ -59,43 +61,42 @@ Alternatively, publish an using a valid PeerID (as listed by `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, false, "ipfs path of the object to be published.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, false, "ipfs path of the object to be published.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("resolve", "Resolve given path before publishing.").Default(true), - cmds.StringOption("lifetime", "t", + Options: []cmdkit.Option{ + cmdkit.BoolOption("resolve", "Resolve given path before publishing.").Default(true), + cmdkit.StringOption("lifetime", "t", `Time duration that the record will be valid for. <> This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`).Default("24h"), - cmds.StringOption("ttl", "Time duration this record should be cached for (caution: experimental)."), - cmds.StringOption("key", "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'. Default: <>.").Default("self"), + cmdkit.StringOption("ttl", "Time duration this record should be cached for (caution: experimental)."), + cmdkit.StringOption("key", "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'. Default: <>.").Default("self"), }, Run: func(req cmds.Request, res cmds.Response) { - log.Debug("begin publish") n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !n.OnlineMode() { err := n.SetupOfflineRouting() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() { - res.SetError(errors.New("cannot manually publish while IPNS is mounted"), cmds.ErrNormal) + res.SetError(errors.New("cannot manually publish while IPNS is mounted"), cmdkit.ErrNormal) return } pstr := req.Arguments()[0] if n.Identity == "" { - res.SetError(errors.New("identity not loaded"), cmds.ErrNormal) + res.SetError(errors.New("identity not loaded"), cmdkit.ErrNormal) return } @@ -106,7 +107,7 @@ Alternatively, publish an using a valid PeerID (as listed by validtime, _, _ := req.Option("lifetime").String() d, err := time.ParseDuration(validtime) if err != nil { - res.SetError(fmt.Errorf("error parsing lifetime option: %s", err), cmds.ErrNormal) + res.SetError(fmt.Errorf("error parsing lifetime option: %s", err), cmdkit.ErrNormal) return } @@ -116,7 +117,7 @@ Alternatively, publish an using a valid PeerID (as listed by if ttl, found, _ := req.Option("ttl").String(); found { d, err := time.ParseDuration(ttl) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -126,27 +127,35 @@ Alternatively, publish an using a valid PeerID (as listed by kname, _, _ := req.Option("key").String() k, err := keylookup(n, kname) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pth, err := path.ParsePath(pstr) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } output, err := publish(ctx, n, k, pth, popts) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(output) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v := res.Output().(*IpnsEntry) - s := fmt.Sprintf("Published to %s: %s\n", v.Name, v.Value) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + entry, ok := v.(*IpnsEntry) + if !ok { + return nil, e.TypeErr(entry, v) + } + + s := fmt.Sprintf("Published to %s: %s\n", entry.Name, entry.Value) return strings.NewReader(s), nil }, }, diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index f018ecfbf..c0ecbca3e 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -1,27 +1,25 @@ package commands import ( - "bytes" "context" "encoding/binary" "fmt" "io" - "strings" "sync" "time" - cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" floodsub "gx/ipfs/QmUUSLfvihARhCxxgnjW4hmycJpPvzNu12Aaz6JWVdfnLg/go-libp2p-floodsub" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" ) var PubsubCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "An experimental publish-subscribe system on ipfs.", ShortDescription: ` ipfs pubsub allows you to publish messages to a given topic, and also to @@ -42,7 +40,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'. } var PubsubSubCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Subscribe to messages on a given topic.", ShortDescription: ` ipfs pubsub sub subscribes to messages on a given topic. @@ -65,58 +63,37 @@ This command outputs data in the following encodings: (Specified by the "--encoding" or "--enc" flag) `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("topic", true, false, "String name of topic to subscribe to."), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("topic", true, false, "String name of topic to subscribe to."), }, - Options: []cmds.Option{ - cmds.BoolOption("discover", "try to discover other peers subscribed to the same topic"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("discover", "try to discover other peers subscribed to the same topic"), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // Must be online! if !n.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } if n.Floodsub == nil { - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) + res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal) return } topic := req.Arguments()[0] sub, err := n.Floodsub.Subscribe(topic) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - - out := make(chan interface{}) - res.SetOutput((<-chan interface{})(out)) - - go func() { - defer sub.Cancel() - defer close(out) - - out <- floodsub.Message{} - - for { - msg, err := sub.Next(req.Context()) - if err == io.EOF || err == context.Canceled { - return - } else if err != nil { - res.SetError(err, cmds.ErrNormal) - return - } - - out <- msg - } - }() + defer sub.Cancel() discover, _, _ := req.Option("discover").Bool() if discover { @@ -131,20 +108,51 @@ This command outputs data in the following encodings: connectToPubSubPeers(req.Context(), n, cid) }() } + + for { + msg, err := sub.Next(req.Context()) + if err == io.EOF || err == context.Canceled { + return + } else if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + res.Emit(msg) + } }, - Marshalers: cmds.MarshalerMap{ - cmds.Text: getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) { - return bytes.NewReader(m.Data), nil + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + m, ok := v.(*floodsub.Message) + if !ok { + return fmt.Errorf("unexpected type: %T", v) + } + + _, err := w.Write(m.Data) + return err }), - "ndpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) { + "ndpayload": cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + m, ok := v.(*floodsub.Message) + if !ok { + return fmt.Errorf("unexpected type: %T", v) + } + m.Data = append(m.Data, '\n') - return bytes.NewReader(m.Data), nil + _, err := w.Write(m.Data) + return err }), - "lenpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) { - buf := make([]byte, 8) + "lenpayload": cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + m, ok := v.(*floodsub.Message) + if !ok { + return fmt.Errorf("unexpected type: %T", v) + } + + buf := make([]byte, 8, len(m.Data)+8) n := binary.PutUvarint(buf, uint64(len(m.Data))) - return io.MultiReader(bytes.NewReader(buf[:n]), bytes.NewReader(m.Data)), nil + buf = append(buf[:n], m.Data...) + _, err := w.Write(buf) + return err }), }, Type: floodsub.Message{}, @@ -174,35 +182,8 @@ func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid *cid.Cid) { wg.Wait() } -func getPsMsgMarshaler(f func(m *floodsub.Message) (io.Reader, error)) func(cmds.Response) (io.Reader, error) { - return func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } - - marshal := func(v interface{}) (io.Reader, error) { - obj, ok := v.(*floodsub.Message) - if !ok { - return nil, u.ErrCast() - } - if obj.Message == nil { - return strings.NewReader(""), nil - } - - return f(obj) - } - - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil - } -} - var PubsubPubCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Publish a message to a given pubsub topic.", ShortDescription: ` ipfs pubsub pub publishes a message to a specified topic. @@ -213,25 +194,25 @@ to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("topic", true, false, "Topic to publish to."), - cmds.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("topic", true, false, "Topic to publish to."), + cmdkit.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // Must be online! if !n.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } if n.Floodsub == nil { - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) + res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal) return } @@ -239,7 +220,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'. for _, data := range req.Arguments()[1:] { if err := n.Floodsub.Publish(topic, []byte(data)); err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -247,7 +228,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'. } var PubsubLsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List subscribed topics by name.", ShortDescription: ` ipfs pubsub ls lists out the names of topics you are currently subscribed to. @@ -258,34 +239,33 @@ to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // Must be online! if !n.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } if n.Floodsub == nil { - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) + res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal) return } - res.SetOutput(&stringList{n.Floodsub.GetTopics()}) - }, - Type: stringList{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: stringListMarshaler, + for _, topic := range n.Floodsub.GetTopics() { + res.Emit(topic) + } }, + Type: "", } var PubsubPeersCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List peers we are currently pubsubbing with.", ShortDescription: ` ipfs pubsub peers with no arguments lists out the pubsub peers you are @@ -298,24 +278,24 @@ to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("topic", false, false, "topic to list connected peers of"), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("topic", false, false, "topic to list connected peers of"), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // Must be online! if !n.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } if n.Floodsub == nil { - res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) + res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal) return } @@ -324,14 +304,12 @@ To use, the daemon must be run with '--enable-pubsub-experiment'. topic = req.Arguments()[0] } - var out []string - for _, p := range n.Floodsub.ListPeers(topic) { - out = append(out, p.Pretty()) + for _, peer := range n.Floodsub.ListPeers(topic) { + res.Emit(peer.Pretty()) } - res.SetOutput(&stringList{out}) }, - Type: stringList{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: stringListMarshaler, + Type: "", + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.Encoders[cmds.TextNewline], }, } diff --git a/core/commands/refs.go b/core/commands/refs.go index 9b0eaa5a7..066e4249f 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -9,12 +9,13 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) // KeyList is a general type for outputting lists of keys @@ -24,7 +25,16 @@ type KeyList struct { // KeyListTextMarshaler outputs a KeyList as plaintext, one key per line func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) { - output := res.Output().(*KeyList) + out, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + output, ok := out.(*KeyList) + if !ok { + return nil, e.TypeErr(output, out) + } + buf := new(bytes.Buffer) for _, key := range output.Keys { buf.WriteString(key.String() + "\n") @@ -33,7 +43,7 @@ func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) { } var RefsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List links (references) from an object.", ShortDescription: ` Lists the hashes of all the links an IPFS or IPNS object(s) contains, @@ -47,50 +57,50 @@ NOTE: List all references recursively by using the flag '-r'. Subcommands: map[string]*cmds.Command{ "local": RefsLocalCmd, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.StringOption("format", "Emit edges with given format. Available tokens: .").Default(""), - cmds.BoolOption("edges", "e", "Emit edge format: ` -> `.").Default(false), - cmds.BoolOption("unique", "u", "Omit duplicate refs from output.").Default(false), - cmds.BoolOption("recursive", "r", "Recursively list links of child nodes.").Default(false), + Options: []cmdkit.Option{ + cmdkit.StringOption("format", "Emit edges with given format. Available tokens: .").Default(""), + cmdkit.BoolOption("edges", "e", "Emit edge format: ` -> `.").Default(false), + cmdkit.BoolOption("unique", "u", "Omit duplicate refs from output.").Default(false), + cmdkit.BoolOption("recursive", "r", "Recursively list links of child nodes.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } unique, _, err := req.Option("unique").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } recursive, _, err := req.Option("recursive").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } format, _, err := req.Option("format").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } edges, _, err := req.Option("edges").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if edges { if format != "" { res.SetError(errors.New("using format arguement with edges is not allowed"), - cmds.ErrClient) + cmdkit.ErrClient) return } @@ -99,7 +109,7 @@ NOTE: List all references recursively by using the flag '-r'. objs, err := objectsForPaths(ctx, n, req.Arguments()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -131,7 +141,7 @@ NOTE: List all references recursively by using the flag '-r'. } var RefsLocalCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List all local references.", ShortDescription: ` Displays the hashes of all local objects. @@ -142,14 +152,14 @@ Displays the hashes of all local objects. ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // todo: make async allKeys, err := n.Blockstore.AllKeysChan(ctx) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -170,29 +180,21 @@ Displays the hashes of all local objects. var refsMarshallerMap = cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + obj, ok := v.(*RefWrapper) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(obj, v) } - marshal := func(v interface{}) (io.Reader, error) { - obj, ok := v.(*RefWrapper) - if !ok { - return nil, u.ErrCast() - } - - if obj.Err != "" { - return nil, errors.New(obj.Err) - } - - return strings.NewReader(obj.Ref + "\n"), nil + if obj.Err != "" { + return nil, errors.New(obj.Err) } - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil + return strings.NewReader(obj.Ref + "\n"), nil }, } diff --git a/core/commands/repo.go b/core/commands/repo.go index 5ca8d35e0..7d764cab1 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -10,14 +10,16 @@ import ( "text/tabwriter" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" - cmds "github.com/ipfs/go-ipfs/commands" + oldcmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" corerepo "github.com/ipfs/go-ipfs/core/corerepo" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" lockfile "github.com/ipfs/go-ipfs/repo/fsrepo/lock" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type RepoVersion struct { @@ -25,7 +27,7 @@ type RepoVersion struct { } var RepoCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Manipulate the IPFS repo.", ShortDescription: ` 'ipfs repo' is a plumbing command used to manipulate the repo. @@ -33,8 +35,10 @@ var RepoCmd = &cmds.Command{ }, Subcommands: map[string]*cmds.Command{ + "stat": repoStatCmd, + }, + OldSubcommands: map[string]*oldcmds.Command{ "gc": repoGcCmd, - "stat": repoStatCmd, "fsck": RepoFsckCmd, "version": repoVersionCmd, "verify": repoVerifyCmd, @@ -47,8 +51,8 @@ type GcResult struct { Error string `json:",omitempty"` } -var repoGcCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var repoGcCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Perform a garbage collection sweep on the repo.", ShortDescription: ` 'ipfs repo gc' is a plumbing command that will sweep the local @@ -56,14 +60,14 @@ set of stored objects and remove ones that are not pinned in order to reclaim hard disk space. `, }, - Options: []cmds.Option{ - cmds.BoolOption("quiet", "q", "Write minimal output.").Default(false), - cmds.BoolOption("stream-errors", "Stream errors.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("stream-errors", "Stream errors.").Default(false), + cmdkit.BoolOption("quiet", "q", "Write minimal output.").Default(false), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -71,11 +75,12 @@ order to reclaim hard disk space. gcOutChan := corerepo.GarbageCollectAsync(n, req.Context()) - outChan := make(chan interface{}, cap(gcOutChan)) - res.SetOutput((<-chan interface{})(outChan)) + outChan := make(chan interface{}) + res.SetOutput(outChan) go func() { defer close(outChan) + if streamErrors { errs := false for res := range gcOutChan { @@ -87,24 +92,24 @@ order to reclaim hard disk space. } } if errs { - res.SetError(fmt.Errorf("encountered errors during gc run"), cmds.ErrNormal) + res.SetError(fmt.Errorf("encountered errors during gc run"), cmdkit.ErrNormal) } } else { err := corerepo.CollectResult(req.Context(), gcOutChan, func(k *cid.Cid) { outChan <- &GcResult{Key: k} }) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) } } }() }, Type: GcResult{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outChan, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() + Marshalers: oldcmds.MarshalerMap{ + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err } quiet, _, err := res.Request().Option("quiet").Bool() @@ -112,35 +117,28 @@ order to reclaim hard disk space. return nil, err } - marshal := func(v interface{}) (io.Reader, error) { - obj, ok := v.(*GcResult) - if !ok { - return nil, u.ErrCast() - } - - if obj.Error != "" { - fmt.Fprintf(res.Stderr(), "Error: %s\n", obj.Error) - return nil, nil - } - - if quiet { - return bytes.NewBufferString(obj.Key.String() + "\n"), nil - } else { - return bytes.NewBufferString(fmt.Sprintf("removed %s\n", obj.Key)), nil - } + obj, ok := v.(*GcResult) + if !ok { + return nil, e.TypeErr(obj, v) } - return &cmds.ChannelMarshaler{ - Channel: outChan, - Marshaler: marshal, - Res: res, - }, nil + if obj.Error != "" { + fmt.Fprintf(res.Stderr(), "Error: %s\n", obj.Error) + return nil, nil + } + + msg := obj.Key.String() + "\n" + if !quiet { + msg = "removed " + msg + } + + return bytes.NewBufferString(msg), nil }, }, } var repoStatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Get stats for the currently used repo.", ShortDescription: ` 'ipfs repo stat' is a plumbing command that will scan the local @@ -151,39 +149,39 @@ RepoSize int Size in bytes that the repo is currently taking. Version string The repo version. `, }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } stat, err := corerepo.RepoStat(n, req.Context()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - res.SetOutput(stat) + res.Emit(stat) }, - Options: []cmds.Option{ - cmds.BoolOption("human", "Output RepoSize in MiB.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("human", "Output RepoSize in MiB.").Default(false), }, Type: corerepo.Stat{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - stat, ok := res.Output().(*corerepo.Stat) + Encoders: cmds.EncoderMap{ + cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { + stat, ok := v.(*corerepo.Stat) if !ok { - return nil, u.ErrCast() + return e.TypeErr(stat, v) } - human, _, err := res.Request().Option("human").Bool() + human, _, err := req.Option("human").Bool() if err != nil { - return nil, err + return err } - buf := new(bytes.Buffer) - wtr := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0) + wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0) + fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects) sizeInMiB := stat.RepoSize / (1024 * 1024) if human && sizeInMiB > 0 { @@ -203,13 +201,14 @@ Version string The repo version. fmt.Fprintf(wtr, "Version:\t%s\n", stat.Version) wtr.Flush() - return buf, nil - }, + return nil + + }), }, } -var RepoFsckCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var RepoFsckCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Remove repo lockfiles.", ShortDescription: ` 'ipfs repo fsck' is a plumbing command that will remove repo and level db @@ -217,12 +216,12 @@ lockfiles, as well as the api file. This command can only run when no ipfs daemons are running. `, }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { configRoot := req.InvocContext().ConfigRoot dsPath, err := config.DataStorePath(configRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -236,135 +235,137 @@ daemons are running. err = os.Remove(repoLockFile) if err != nil && !os.IsNotExist(err) { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = os.Remove(dsLockFile) if err != nil && !os.IsNotExist(err) { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = os.Remove(apiFile) if err != nil && !os.IsNotExist(err) { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&MessageOutput{"Lockfiles have been removed.\n"}) }, Type: MessageOutput{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: MessageTextMarshaler, + Marshalers: oldcmds.MarshalerMap{ + oldcmds.Text: MessageTextMarshaler, }, } type VerifyProgress struct { - Message string + Msg string Progress int } -var repoVerifyCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var repoVerifyCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Verify all blocks in repo are not corrupted.", }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } out := make(chan interface{}) - go func() { - defer close(out) - bs := bstore.NewBlockstore(nd.Repo.Datastore()) - - bs.HashOnRead(true) - - keys, err := bs.AllKeysChan(req.Context()) - if err != nil { - log.Error(err) - return - } - - var fails int - var i int - for k := range keys { - _, err := bs.Get(k) - if err != nil { - out <- &VerifyProgress{ - Message: fmt.Sprintf("block %s was corrupt (%s)", k, err), - } - fails++ - } - i++ - out <- &VerifyProgress{Progress: i} - } - if fails == 0 { - out <- &VerifyProgress{Message: "verify complete, all blocks validated."} - } else { - out <- &VerifyProgress{Message: "verify complete, some blocks were corrupt."} - } - }() - res.SetOutput((<-chan interface{})(out)) + defer close(out) + + bs := bstore.NewBlockstore(nd.Repo.Datastore()) + bs.HashOnRead(true) + + keys, err := bs.AllKeysChan(req.Context()) + if err != nil { + log.Error(err) + return + } + + var fails int + var i int + for k := range keys { + _, err := bs.Get(k) + if err != nil { + out <- &VerifyProgress{ + Msg: fmt.Sprintf("block %s was corrupt (%s)", k, err), + } + fails++ + } + i++ + out <- &VerifyProgress{Progress: i} + } + + if fails == 0 { + out <- &VerifyProgress{Msg: "verify complete, all blocks validated."} + } else { + res.SetError(fmt.Errorf("verify complete, some blocks were corrupt"), cmdkit.ErrNormal) + } }, - Type: VerifyProgress{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - out := res.Output().(<-chan interface{}) + Type: &VerifyProgress{}, + Marshalers: oldcmds.MarshalerMap{ + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } - marshal := func(v interface{}) (io.Reader, error) { - obj, ok := v.(*VerifyProgress) - if !ok { - return nil, u.ErrCast() - } + obj, ok := v.(*VerifyProgress) + if !ok { + return nil, e.TypeErr(obj, v) + } - buf := new(bytes.Buffer) - if obj.Message != "" { - if strings.Contains(obj.Message, "blocks were corrupt") { - return nil, fmt.Errorf(obj.Message) - } - if len(obj.Message) < 20 { - obj.Message += " " - } - fmt.Fprintln(buf, obj.Message) - return buf, nil - } - - fmt.Fprintf(buf, "%d blocks processed.\r", obj.Progress) + buf := new(bytes.Buffer) + if strings.Contains(obj.Msg, "was corrupt") { + fmt.Fprintln(os.Stdout, obj.Msg) return buf, nil } - return &cmds.ChannelMarshaler{ - Channel: out, - Marshaler: marshal, - Res: res, - }, nil + if obj.Msg != "" { + if len(obj.Msg) < 20 { + obj.Msg += " " + } + fmt.Fprintln(buf, obj.Msg) + return buf, nil + } + + fmt.Fprintf(buf, "%d blocks processed.\r", obj.Progress) + return buf, nil }, }, } -var repoVersionCmd = &cmds.Command{ - Helptext: cmds.HelpText{ +var repoVersionCmd = &oldcmds.Command{ + Helptext: cmdkit.HelpText{ Tagline: "Show the repo version.", ShortDescription: ` 'ipfs repo version' returns the current repo version. `, }, - Options: []cmds.Option{ - cmds.BoolOption("quiet", "q", "Write minimal output."), + Options: []cmdkit.Option{ + cmdkit.BoolOption("quiet", "q", "Write minimal output."), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req oldcmds.Request, res oldcmds.Response) { res.SetOutput(&RepoVersion{ Version: fmt.Sprint(fsrepo.RepoVersion), }) }, Type: RepoVersion{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - response := res.Output().(*RepoVersion) + Marshalers: oldcmds.MarshalerMap{ + oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + response, ok := v.(*RepoVersion) + if !ok { + return nil, e.TypeErr(response, v) + } quiet, _, err := res.Request().Option("quiet").Bool() if err != nil { diff --git a/core/commands/resolve.go b/core/commands/resolve.go index affaf0deb..d667cc633 100644 --- a/core/commands/resolve.go +++ b/core/commands/resolve.go @@ -6,9 +6,11 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" ns "github.com/ipfs/go-ipfs/namesys" path "github.com/ipfs/go-ipfs/path" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type ResolvedPath struct { @@ -16,7 +18,7 @@ type ResolvedPath struct { } var ResolveCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Resolve the value of names to IPFS.", ShortDescription: ` There are a number of mutable name protocols that can link among @@ -55,24 +57,24 @@ Resolve the value of an IPFS DAG path: `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("name", true, false, "The name to resolve.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(), }, - Options: []cmds.Option{ - cmds.BoolOption("recursive", "r", "Resolve until the result is an IPFS name.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if !n.OnlineMode() { err := n.SetupOfflineRouting() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } } @@ -85,7 +87,7 @@ Resolve the value of an IPFS DAG path: p, err := n.Namesys.ResolveN(req.Context(), name, 1) // ErrResolveRecursion is fine if err != nil && err != ns.ErrResolveRecursion { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } res.SetOutput(&ResolvedPath{p}) @@ -95,13 +97,13 @@ Resolve the value of an IPFS DAG path: // else, ipfs path or ipns with recursive flag p, err := path.ParsePath(name) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, p) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -111,9 +113,14 @@ Resolve the value of an IPFS DAG path: }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - output, ok := res.Output().(*ResolvedPath) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + output, ok := v.(*ResolvedPath) if !ok { - return nil, u.ErrCast() + return nil, e.TypeErr(output, v) } return strings.NewReader(output.Path.String() + "\n"), nil }, diff --git a/core/commands/root.go b/core/commands/root.go index 8fa5a050f..09f233728 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -4,11 +4,15 @@ import ( "io" "strings" - cmds "github.com/ipfs/go-ipfs/commands" + oldcmds "github.com/ipfs/go-ipfs/commands" dag "github.com/ipfs/go-ipfs/core/commands/dag" + e "github.com/ipfs/go-ipfs/core/commands/e" files "github.com/ipfs/go-ipfs/core/commands/files" ocmd "github.com/ipfs/go-ipfs/core/commands/object" unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs" + + "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ) @@ -19,7 +23,7 @@ const ( ) var Root = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Global p2p merkle-dag filesystem.", Synopsis: "ipfs [--config= | -c] [--debug= | -D] [--help=] [-h=] [--local= | -L] [--api=] ...", Subcommands: ` @@ -80,13 +84,13 @@ The CLI will exit with one of the following values: 1 Failed executions. `, }, - Options: []cmds.Option{ - cmds.StringOption("config", "c", "Path to the configuration file to use."), - cmds.BoolOption("debug", "D", "Operate in debug mode.").Default(false), - cmds.BoolOption("help", "Show the full command help text.").Default(false), - cmds.BoolOption("h", "Show a short version of the command help text.").Default(false), - cmds.BoolOption("local", "L", "Run the command locally, instead of using the daemon.").Default(false), - cmds.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"), + Options: []cmdkit.Option{ + cmdkit.StringOption("config", "c", "Path to the configuration file to use."), + cmdkit.BoolOption("debug", "D", "Operate in debug mode.").Default(false), + cmdkit.BoolOption("help", "Show the full command help text.").Default(false), + cmdkit.BoolOption("h", "Show a short version of the command help text.").Default(false), + cmdkit.BoolOption("local", "L", "Run the command locally, instead of using the daemon.").Default(false), + cmdkit.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"), }, } @@ -95,17 +99,25 @@ var CommandsDaemonCmd = CommandsCmd(Root) var rootSubcommands = map[string]*cmds.Command{ "add": AddCmd, + "bitswap": BitswapCmd, "block": BlockCmd, - "bootstrap": BootstrapCmd, "cat": CatCmd, "commands": CommandsDaemonCmd, + "filestore": FileStoreCmd, + "get": GetCmd, + "pubsub": PubsubCmd, + "repo": RepoCmd, + "stats": StatsCmd, +} + +var rootOldSubcommands = map[string]*oldcmds.Command{ + "bootstrap": BootstrapCmd, "config": ConfigCmd, "dag": dag.DagCmd, "dht": DhtCmd, "diag": DiagCmd, "dns": DNSCmd, "files": files.FilesCmd, - "get": GetCmd, "id": IDCmd, "key": KeyCmd, "log": LogCmd, @@ -116,18 +128,13 @@ var rootSubcommands = map[string]*cmds.Command{ "pin": PinCmd, "ping": PingCmd, "p2p": P2PCmd, - "pubsub": PubsubCmd, "refs": RefsCmd, - "repo": RepoCmd, "resolve": ResolveCmd, - "stats": StatsCmd, "swarm": SwarmCmd, "tar": TarCmd, "file": unixfs.UnixFSCmd, "update": ExternalBinary(), "version": VersionCmd, - "bitswap": BitswapCmd, - "filestore": FileStoreCmd, "shutdown": daemonShutdownCmd, } @@ -136,27 +143,30 @@ var RootRO = &cmds.Command{} var CommandsDaemonROCmd = CommandsCmd(RootRO) -var RefsROCmd = &cmds.Command{} +var RefsROCmd = &oldcmds.Command{} var rootROSubcommands = map[string]*cmds.Command{ + "commands": CommandsDaemonROCmd, + "cat": CatCmd, "block": &cmds.Command{ Subcommands: map[string]*cmds.Command{ "stat": blockStatCmd, "get": blockGetCmd, }, }, - "cat": CatCmd, - "commands": CommandsDaemonROCmd, - "dns": DNSCmd, - "get": GetCmd, - "ls": LsCmd, - "name": &cmds.Command{ - Subcommands: map[string]*cmds.Command{ + "get": GetCmd, +} + +var rootROOldSubcommands = map[string]*oldcmds.Command{ + "dns": DNSCmd, + "ls": LsCmd, + "name": &oldcmds.Command{ + Subcommands: map[string]*oldcmds.Command{ "resolve": IpnsCmd, }, }, - "object": &cmds.Command{ - Subcommands: map[string]*cmds.Command{ + "object": &oldcmds.Command{ + Subcommands: map[string]*oldcmds.Command{ "data": ocmd.ObjectDataCmd, "links": ocmd.ObjectLinksCmd, "get": ocmd.ObjectGetCmd, @@ -164,8 +174,8 @@ var rootROSubcommands = map[string]*cmds.Command{ "patch": ocmd.ObjectPatchCmd, }, }, - "dag": &cmds.Command{ - Subcommands: map[string]*cmds.Command{ + "dag": &oldcmds.Command{ + Subcommands: map[string]*oldcmds.Command{ "get": dag.DagGetCmd, "resolve": dag.DagResolveCmd, }, @@ -181,9 +191,12 @@ func init() { // sanitize readonly refs command *RefsROCmd = *RefsCmd - RefsROCmd.Subcommands = map[string]*cmds.Command{} + RefsROCmd.Subcommands = map[string]*oldcmds.Command{} + Root.OldSubcommands = rootOldSubcommands Root.Subcommands = rootSubcommands + + RootRO.OldSubcommands = rootROOldSubcommands RootRO.Subcommands = rootROSubcommands } @@ -191,6 +204,16 @@ type MessageOutput struct { Message string } -func MessageTextMarshaler(res cmds.Response) (io.Reader, error) { - return strings.NewReader(res.Output().(*MessageOutput).Message), nil +func MessageTextMarshaler(res oldcmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + out, ok := v.(*MessageOutput) + if !ok { + return nil, e.TypeErr(out, v) + } + + return strings.NewReader(out.Message), nil } diff --git a/core/commands/shutdown.go b/core/commands/shutdown.go index 43c3c205a..a6277c1a0 100644 --- a/core/commands/shutdown.go +++ b/core/commands/shutdown.go @@ -3,27 +3,31 @@ package commands import ( "fmt" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "github.com/ipfs/go-ipfs/commands" ) var daemonShutdownCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Shut down the ipfs daemon", }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if nd.LocalMode() { - res.SetError(fmt.Errorf("daemon not running"), cmds.ErrClient) + res.SetError(fmt.Errorf("daemon not running"), cmdkit.ErrClient) return } if err := nd.Process().Close(); err != nil { log.Error("error while shutting down ipfs daemon:", err) } + + res.SetOutput(nil) }, } diff --git a/core/commands/stat.go b/core/commands/stat.go index eec6fcffe..b41bf56cc 100644 --- a/core/commands/stat.go +++ b/core/commands/stat.go @@ -1,23 +1,22 @@ package commands import ( - "bytes" "errors" "fmt" "io" + "os" "time" humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize" - - cmds "github.com/ipfs/go-ipfs/commands" + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" metrics "gx/ipfs/QmQbh3Rb7KM37As3vkHYnEFnzkVXNCP8EYGtHz6g2fXk14/go-libp2p-metrics" - u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol" ) var StatsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Query IPFS statistics.", ShortDescription: `'ipfs stats' is a set of commands to help look at statistics for your IPFS node. @@ -34,7 +33,7 @@ for your IPFS node.`, } var statBwCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Print ipfs bandwidth information.", ShortDescription: `'ipfs stats bw' prints bandwidth information for the ipfs daemon. It displays: TotalIn, TotalOut, RateIn, RateOut. @@ -70,47 +69,47 @@ Example: RateOut: 0B/s `, }, - Options: []cmds.Option{ - cmds.StringOption("peer", "p", "Specify a peer to print bandwidth for."), - cmds.StringOption("proto", "t", "Specify a protocol to print bandwidth for."), - cmds.BoolOption("poll", "Print bandwidth at an interval.").Default(false), - cmds.StringOption("interval", "i", `Time interval to wait between updating output, if 'poll' is true. + Options: []cmdkit.Option{ + cmdkit.StringOption("peer", "p", "Specify a peer to print bandwidth for."), + cmdkit.StringOption("proto", "t", "Specify a protocol to print bandwidth for."), + cmdkit.BoolOption("poll", "Print bandwidth at an interval.").Default(false), + cmdkit.StringOption("interval", "i", `Time interval to wait between updating output, if 'poll' is true. This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are: "ns", "us" (or "µs"), "ms", "s", "m", "h".`).Default("1s"), }, - Run: func(req cmds.Request, res cmds.Response) { + Run: func(req cmds.Request, res cmds.ResponseEmitter) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } // Must be online! if !nd.OnlineMode() { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } if nd.Reporter == nil { - res.SetError(fmt.Errorf("bandwidth reporter disabled in config"), cmds.ErrNormal) + res.SetError(fmt.Errorf("bandwidth reporter disabled in config"), cmdkit.ErrNormal) return } pstr, pfound, err := req.Option("peer").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } tstr, tfound, err := req.Option("proto").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if pfound && tfound { - res.SetError(errors.New("please only specify peer OR protocol"), cmds.ErrClient) + res.SetError(errors.New("please only specify peer OR protocol"), cmdkit.ErrClient) return } @@ -118,7 +117,7 @@ Example: if pfound { checkpid, err := peer.IDB58Decode(pstr) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } pid = checkpid @@ -126,92 +125,79 @@ Example: timeS, _, err := req.Option("interval").String() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } interval, err := time.ParseDuration(timeS) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } doPoll, _, err := req.Option("poll").Bool() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } - out := make(chan interface{}) - res.SetOutput((<-chan interface{})(out)) - - go func() { - defer close(out) - for { - if pfound { - stats := nd.Reporter.GetBandwidthForPeer(pid) - out <- &stats - } else if tfound { - protoId := protocol.ID(tstr) - stats := nd.Reporter.GetBandwidthForProtocol(protoId) - out <- &stats - } else { - totals := nd.Reporter.GetBandwidthTotals() - out <- &totals - } - if !doPoll { - return - } - select { - case <-time.After(interval): - case <-req.Context().Done(): - return - } + for { + if pfound { + stats := nd.Reporter.GetBandwidthForPeer(pid) + res.Emit(&stats) + } else if tfound { + protoId := protocol.ID(tstr) + stats := nd.Reporter.GetBandwidthForProtocol(protoId) + res.Emit(&stats) + } else { + totals := nd.Reporter.GetBandwidthTotals() + res.Emit(&totals) } - }() + if !doPoll { + return + } + select { + case <-time.After(interval): + case <-req.Context().Done(): + return + } + } + }, Type: metrics.Stats{}, - Marshalers: cmds.MarshalerMap{ - cmds.Text: func(res cmds.Response) (io.Reader, error) { - outCh, ok := res.Output().(<-chan interface{}) - if !ok { - return nil, u.ErrCast() - } + PostRun: cmds.PostRunMap{ + cmds.CLI: func(req cmds.Request, re cmds.ResponseEmitter) cmds.ResponseEmitter { + reNext, res := cmds.NewChanResponsePair(req) - polling, _, err := res.Request().Option("poll").Bool() - if err != nil { - return nil, err - } + go func() { + defer re.Close() - first := true - marshal := func(v interface{}) (io.Reader, error) { - bs, ok := v.(*metrics.Stats) - if !ok { - return nil, u.ErrCast() + polling, _, err := res.Request().Option("poll").Bool() + if err != nil { + return } - out := new(bytes.Buffer) - if !polling { - printStats(out, bs) - } else { - if first { - fmt.Fprintln(out, "Total Up Total Down Rate Up Rate Down") - first = false + + fmt.Fprintln(os.Stdout, "Total Up Total Down Rate Up Rate Down") + for { + v, err := res.Next() + if !cmds.HandleError(err, res, re) { + break } - fmt.Fprint(out, "\r") - // In the worst case scenario, the humanized output is of form "xxx.x xB", which is 8 characters long - fmt.Fprintf(out, "%8s ", humanize.Bytes(uint64(bs.TotalOut))) - fmt.Fprintf(out, "%8s ", humanize.Bytes(uint64(bs.TotalIn))) - fmt.Fprintf(out, "%8s/s ", humanize.Bytes(uint64(bs.RateOut))) - fmt.Fprintf(out, "%8s/s ", humanize.Bytes(uint64(bs.RateIn))) + + bs := v.(*metrics.Stats) + + if !polling { + printStats(os.Stdout, bs) + return + } + + fmt.Fprintf(os.Stdout, "%8s ", humanize.Bytes(uint64(bs.TotalOut))) + fmt.Fprintf(os.Stdout, "%8s ", humanize.Bytes(uint64(bs.TotalIn))) + fmt.Fprintf(os.Stdout, "%8s/s ", humanize.Bytes(uint64(bs.RateOut))) + fmt.Fprintf(os.Stdout, "%8s/s \n", humanize.Bytes(uint64(bs.RateIn))) } - return out, nil + }() - } - - return &cmds.ChannelMarshaler{ - Channel: outCh, - Marshaler: marshal, - Res: res, - }, nil + return reNext }, }, } diff --git a/core/commands/swarm.go b/core/commands/swarm.go index 42ab6ea1f..29aef9038 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -10,15 +10,17 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" repo "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/repo/fsrepo" + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" + mafilter "gx/ipfs/QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv/multiaddr-filter" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" swarm "gx/ipfs/QmdQFrFnPrKRQtpeHKjZ3cVNwxmGKKS2TvhJTuN9C9yduh/go-libp2p-swarm" iaddr "gx/ipfs/QmeS8cCKawUwejVrsBtmC1toTXmwVWZGiRJqzgTURVWeF9/go-ipfs-addr" - - mafilter "gx/ipfs/QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv/multiaddr-filter" - ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" ) type stringList struct { @@ -30,7 +32,7 @@ type addrMap struct { } var SwarmCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with the swarm.", ShortDescription: ` 'ipfs swarm' is a tool to manipulate the network swarm. The swarm is the @@ -48,28 +50,27 @@ ipfs peers in the internet. } var swarmPeersCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List peers with open connections.", ShortDescription: ` 'ipfs swarm peers' lists the set of peers this node is connected to. `, }, - Options: []cmds.Option{ - cmds.BoolOption("verbose", "v", "display all extra information"), - cmds.BoolOption("streams", "Also list information about open streams for each peer"), - cmds.BoolOption("latency", "Also list information about latency to each peer"), + Options: []cmdkit.Option{ + cmdkit.BoolOption("verbose", "v", "display all extra information"), + cmdkit.BoolOption("streams", "Also list information about open streams for each peer"), + cmdkit.BoolOption("latency", "Also list information about latency to each peer"), }, Run: func(req cmds.Request, res cmds.Response) { - log.Debug("ipfs swarm peers") n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } @@ -105,7 +106,7 @@ var swarmPeersCmd = &cmds.Command{ if verbose || streams { strs, err := c.GetStreams() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -122,9 +123,14 @@ var swarmPeersCmd = &cmds.Command{ }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - ci, ok := res.Output().(*connInfos) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + ci, ok := v.(*connInfos) if !ok { - return nil, fmt.Errorf("expected output type to be connInfos") + return nil, e.TypeErr(ci, v) } buf := new(bytes.Buffer) @@ -197,7 +203,7 @@ func (ci connInfos) Swap(i, j int) { } var swarmAddrsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List known addresses. Useful for debugging.", ShortDescription: ` 'ipfs swarm addrs' lists all addresses this node is aware of. @@ -211,12 +217,12 @@ var swarmAddrsCmd = &cmds.Command{ n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } @@ -234,9 +240,14 @@ var swarmAddrsCmd = &cmds.Command{ }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - m, ok := res.Output().(*addrMap) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + m, ok := v.(*addrMap) if !ok { - return nil, errors.New("failed to cast map[string]string") + return nil, e.TypeErr(m, v) } // sort the ids first @@ -261,25 +272,25 @@ var swarmAddrsCmd = &cmds.Command{ } var swarmAddrsLocalCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List local addresses.", ShortDescription: ` 'ipfs swarm addrs local' lists all local listening addresses announced to the network. `, }, - Options: []cmds.Option{ - cmds.BoolOption("id", "Show peer ID in addresses.").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("id", "Show peer ID in addresses.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { - - n, err := req.InvocContext().GetNode() + iCtx := req.InvocContext() + n, err := iCtx.GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } @@ -295,7 +306,6 @@ var swarmAddrsLocalCmd = &cmds.Command{ addrs = append(addrs, saddr) } sort.Sort(sort.StringSlice(addrs)) - res.SetOutput(&stringList{addrs}) }, Type: stringList{}, @@ -305,7 +315,7 @@ var swarmAddrsLocalCmd = &cmds.Command{ } var swarmAddrsListenCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List interface listening addresses.", ShortDescription: ` 'ipfs swarm addrs listen' lists all interface addresses the node is listening on. @@ -315,19 +325,19 @@ var swarmAddrsListenCmd = &cmds.Command{ n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } var addrs []string maddrs, err := n.PeerHost.Network().InterfaceListenAddresses() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -345,7 +355,7 @@ var swarmAddrsListenCmd = &cmds.Command{ } var swarmConnectCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Open connection to a given address.", ShortDescription: ` 'ipfs swarm connect' opens a new direct connection to a peer address. @@ -355,28 +365,28 @@ The address format is an IPFS multiaddr: ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("address", true, true, "Address of peer to connect to.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("address", true, true, "Address of peer to connect to.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } addrs := req.Arguments() if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } snet, ok := n.PeerHost.Network().(*swarm.Network) if !ok { - res.SetError(fmt.Errorf("peerhost network was not swarm"), cmds.ErrNormal) + res.SetError(fmt.Errorf("peerhost network was not swarm"), cmdkit.ErrNormal) return } @@ -384,7 +394,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3 pis, err := peersWithAddresses(addrs) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -396,7 +406,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3 err := n.PeerHost.Connect(ctx, pi) if err != nil { - res.SetError(fmt.Errorf("%s failure: %s", output[i], err), cmds.ErrNormal) + res.SetError(fmt.Errorf("%s failure: %s", output[i], err), cmdkit.ErrNormal) return } output[i] += " success" @@ -411,7 +421,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3 } var swarmDisconnectCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Close connection to a given address.", ShortDescription: ` 'ipfs swarm disconnect' closes a connection to a peer address. The address @@ -423,26 +433,26 @@ The disconnect is not permanent; if ipfs needs to talk to that address later, it will reconnect. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("address", true, true, "Address of peer to disconnect from.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("address", true, true, "Address of peer to disconnect from.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } addrs := req.Arguments() if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrClient) + res.SetError(errNotOnline, cmdkit.ErrClient) return } iaddrs, err := parseAddresses(addrs) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -455,7 +465,6 @@ it will reconnect. conns := n.PeerHost.Network().ConnsToPeer(addr.ID()) for _, conn := range conns { if !conn.RemoteMultiaddr().Equal(taddr) { - log.Debug("it's not", conn.RemoteMultiaddr(), taddr) continue } @@ -481,9 +490,14 @@ it will reconnect. } func stringListMarshaler(res cmds.Response) (io.Reader, error) { - list, ok := res.Output().(*stringList) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + list, ok := v.(*stringList) if !ok { - return nil, errors.New("failed to cast []string") + return nil, e.TypeErr(list, v) } buf := new(bytes.Buffer) @@ -491,6 +505,7 @@ func stringListMarshaler(res cmds.Response) (io.Reader, error) { buf.WriteString(s) buf.WriteString("\n") } + return buf, nil } @@ -525,7 +540,7 @@ func peersWithAddresses(addrs []string) (pis []pstore.PeerInfo, err error) { } var swarmFiltersCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Manipulate address filters.", ShortDescription: ` 'ipfs swarm filters' will list out currently applied filters. Its subcommands @@ -550,18 +565,18 @@ Filters default to those specified under the "Swarm.AddrFilters" config key. Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrNormal) + res.SetError(errNotOnline, cmdkit.ErrNormal) return } snet, ok := n.PeerHost.Network().(*swarm.Network) if !ok { - res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal) + res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal) return } @@ -569,7 +584,7 @@ Filters default to those specified under the "Swarm.AddrFilters" config key. for _, f := range snet.Filters.Filters() { s, err := mafilter.ConvertIPNet(f) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } output = append(output, s) @@ -583,7 +598,7 @@ Filters default to those specified under the "Swarm.AddrFilters" config key. } var swarmFiltersAddCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Add an address filter.", ShortDescription: ` 'ipfs swarm filters add' will add an address filter to the daemons swarm. @@ -591,48 +606,48 @@ Filters applied this way will not persist daemon reboots, to achieve that, add your filters to the ipfs config file. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("address", true, true, "Multiaddr to filter.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("address", true, true, "Multiaddr to filter.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrNormal) + res.SetError(errNotOnline, cmdkit.ErrNormal) return } snet, ok := n.PeerHost.Network().(*swarm.Network) if !ok { - res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal) + res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal) return } if len(req.Arguments()) == 0 { - res.SetError(errors.New("no filters to add"), cmds.ErrClient) + res.SetError(errors.New("no filters to add"), cmdkit.ErrClient) return } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } for _, arg := range req.Arguments() { mask, err := mafilter.NewMask(arg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -641,7 +656,7 @@ add your filters to the ipfs config file. added, err := filtersAdd(r, cfg, req.Arguments()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -655,7 +670,7 @@ add your filters to the ipfs config file. } var swarmFiltersRmCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Remove an address filter.", ShortDescription: ` 'ipfs swarm filters rm' will remove an address filter from the daemons swarm. @@ -663,36 +678,36 @@ Filters removed this way will not persist daemon reboots, to achieve that, remove your filters from the ipfs config file. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("address", true, true, "Multiaddr filter to remove.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("address", true, true, "Multiaddr filter to remove.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } if n.PeerHost == nil { - res.SetError(errNotOnline, cmds.ErrNormal) + res.SetError(errNotOnline, cmdkit.ErrNormal) return } snet, ok := n.PeerHost.Network().(*swarm.Network) if !ok { - res.SetError(errors.New("failed to cast network to swarm network"), cmds.ErrNormal) + res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal) return } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } defer r.Close() cfg, err := r.Config() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -704,7 +719,7 @@ remove your filters from the ipfs config file. removed, err := filtersRemoveAll(r, cfg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -716,7 +731,7 @@ remove your filters from the ipfs config file. for _, arg := range req.Arguments() { mask, err := mafilter.NewMask(arg) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -725,7 +740,7 @@ remove your filters from the ipfs config file. removed, err := filtersRemove(r, cfg, req.Arguments()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } diff --git a/core/commands/sysdiag.go b/core/commands/sysdiag.go index bd0c68bc2..083f506d0 100644 --- a/core/commands/sysdiag.go +++ b/core/commands/sysdiag.go @@ -8,12 +8,13 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" config "github.com/ipfs/go-ipfs/repo/config" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" manet "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net" sysi "gx/ipfs/QmZRjKbHa6DenStpQJFiaPcEwkZqrx7TH6xTf342LDU3qM/go-sysinfo" ) var sysDiagCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Print system diagnostic information.", ShortDescription: ` Prints out information about your computer to aid in easier debugging. @@ -23,36 +24,36 @@ Prints out information about your computer to aid in easier debugging. info := make(map[string]interface{}) err := runtimeInfo(info) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = envVarInfo(info) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = diskSpaceInfo(info) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = memInfo(info) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } err = netInfo(node.OnlineMode(), info) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } diff --git a/core/commands/tar.go b/core/commands/tar.go index 2a29768f8..c3912b2b6 100644 --- a/core/commands/tar.go +++ b/core/commands/tar.go @@ -6,14 +6,17 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" "github.com/ipfs/go-ipfs/core/coreunix" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" tar "github.com/ipfs/go-ipfs/tar" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) var TarCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Utility functions for tar files in ipfs.", }, @@ -24,7 +27,7 @@ var TarCmd = &cmds.Command{ } var tarAddCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Import a tar file into ipfs.", ShortDescription: ` 'ipfs tar add' will parse a tar file and create a merkledag structure to @@ -32,25 +35,25 @@ represent it. `, }, - Arguments: []cmds.Argument{ - cmds.FileArg("file", true, false, "Tar file to add.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.FileArg("file", true, false, "Tar file to add.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } fi, err := req.Files().NextFile() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } node, err := tar.ImportTar(fi, nd.DAG) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -65,51 +68,59 @@ represent it. Type: coreunix.AddedObject{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - o := res.Output().(*coreunix.AddedObject) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + o, ok := v.(*coreunix.AddedObject) + if !ok { + return nil, e.TypeErr(o, v) + } return strings.NewReader(o.Hash + "\n"), nil }, }, } var tarCatCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Export a tar file from IPFS.", ShortDescription: ` 'ipfs tar cat' will export a tar file from a previously imported one in IPFS. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("path", true, false, "ipfs path of archive to export.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("path", true, false, "ipfs path of archive to export.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } p, err := path.ParsePath(req.Arguments()[0]) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } root, err := core.Resolve(req.Context(), nd.Namesys, nd.Resolver, p) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } rootpb, ok := root.(*dag.ProtoNode) if !ok { - res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(dag.ErrNotProtobuf, cmdkit.ErrNormal) return } r, err := tar.ExportTar(req.Context(), rootpb, nd.DAG) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } diff --git a/core/commands/unixfs/ls.go b/core/commands/unixfs/ls.go index 1fdb81ee9..98f44a397 100644 --- a/core/commands/unixfs/ls.go +++ b/core/commands/unixfs/ls.go @@ -9,11 +9,13 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" + e "github.com/ipfs/go-ipfs/core/commands/e" merkledag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" unixfs "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" unixfspb "github.com/ipfs/go-ipfs/unixfs/pb" + cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type LsLink struct { @@ -35,7 +37,7 @@ type LsOutput struct { } var LsCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "List directory contents for Unix filesystem objects.", ShortDescription: ` Displays the contents of an IPFS or IPNS object(s) at the given path. @@ -69,13 +71,13 @@ possible, please use 'ipfs ls' instead. `, }, - Arguments: []cmds.Argument{ - cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(), + Arguments: []cmdkit.Argument{ + cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { node, err := req.InvocContext().GetNode() if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -96,7 +98,7 @@ possible, please use 'ipfs ls' instead. merkleNode, err := core.Resolve(ctx, node.Namesys, resolver, path.Path(fpath)) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -112,13 +114,13 @@ possible, please use 'ipfs ls' instead. ndpb, ok := merkleNode.(*merkledag.ProtoNode) if !ok { - res.SetError(merkledag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(merkledag.ErrNotProtobuf, cmdkit.ErrNormal) return } unixFSNode, err := unixfs.FromBytes(ndpb.Data()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } @@ -139,18 +141,18 @@ possible, please use 'ipfs ls' instead. for i, link := range merkleNode.Links() { linkNode, err := link.GetNode(ctx, node.DAG) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } lnpb, ok := linkNode.(*merkledag.ProtoNode) if !ok { - res.SetError(merkledag.ErrNotProtobuf, cmds.ErrNormal) + res.SetError(merkledag.ErrNotProtobuf, cmdkit.ErrNormal) return } d, err := unixfs.FromBytes(lnpb.Data()) if err != nil { - res.SetError(err, cmds.ErrNormal) + res.SetError(err, cmdkit.ErrNormal) return } t := d.GetType() @@ -167,10 +169,10 @@ possible, please use 'ipfs ls' instead. links[i] = lsLink } case unixfspb.Data_Symlink: - res.SetError(fmt.Errorf("cannot list symlinks yet"), cmds.ErrNormal) + res.SetError(fmt.Errorf("cannot list symlinks yet"), cmdkit.ErrNormal) return default: - res.SetError(fmt.Errorf("unrecognized type: %s", t), cmds.ErrImplementation) + res.SetError(fmt.Errorf("unrecognized type: %s", t), cmdkit.ErrImplementation) return } } @@ -179,8 +181,15 @@ possible, please use 'ipfs ls' instead. }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } - output := res.Output().(*LsOutput) + output, ok := v.(*LsOutput) + if !ok { + return nil, e.TypeErr(output, v) + } buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0) diff --git a/core/commands/unixfs/unixfs.go b/core/commands/unixfs/unixfs.go index a5f9cf567..f49fd2ceb 100644 --- a/core/commands/unixfs/unixfs.go +++ b/core/commands/unixfs/unixfs.go @@ -1,9 +1,14 @@ package unixfs -import cmds "github.com/ipfs/go-ipfs/commands" +import ( + cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" + + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" +) var UnixFSCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Interact with IPFS objects representing Unix filesystems.", ShortDescription: ` 'ipfs file' provides a familiar interface to file systems represented @@ -21,3 +26,17 @@ objects (e.g. fanout and chunking). "ls": LsCmd, }, } + +// copy+pasted from ../commands.go +func unwrapOutput(i interface{}) (interface{}, error) { + var ( + ch <-chan interface{} + ok bool + ) + + if ch, ok = i.(<-chan interface{}); !ok { + return nil, e.TypeErr(ch, i) + } + + return <-ch, nil +} diff --git a/core/commands/version.go b/core/commands/version.go index c511b8a98..822973c15 100644 --- a/core/commands/version.go +++ b/core/commands/version.go @@ -7,8 +7,10 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" + e "github.com/ipfs/go-ipfs/core/commands/e" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" ) type VersionOutput struct { @@ -20,16 +22,16 @@ type VersionOutput struct { } var VersionCmd = &cmds.Command{ - Helptext: cmds.HelpText{ + Helptext: cmdkit.HelpText{ Tagline: "Show ipfs version information.", ShortDescription: "Returns the current version of ipfs and exits.", }, - Options: []cmds.Option{ - cmds.BoolOption("number", "n", "Only show the version number.").Default(false), - cmds.BoolOption("commit", "Show the commit hash.").Default(false), - cmds.BoolOption("repo", "Show repo version.").Default(false), - cmds.BoolOption("all", "Show all version information").Default(false), + Options: []cmdkit.Option{ + cmdkit.BoolOption("number", "n", "Only show the version number.").Default(false), + cmdkit.BoolOption("commit", "Show the commit hash.").Default(false), + cmdkit.BoolOption("repo", "Show repo version.").Default(false), + cmdkit.BoolOption("all", "Show all version information").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { res.SetOutput(&VersionOutput{ @@ -42,7 +44,15 @@ var VersionCmd = &cmds.Command{ }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { - v := res.Output().(*VersionOutput) + v, err := unwrapOutput(res.Output()) + if err != nil { + return nil, err + } + + version, ok := v.(*VersionOutput) + if !ok { + return nil, e.TypeErr(version, v) + } repo, _, err := res.Request().Option("repo").Bool() if err != nil { @@ -50,7 +60,7 @@ var VersionCmd = &cmds.Command{ } if repo { - return strings.NewReader(v.Repo + "\n"), nil + return strings.NewReader(version.Repo + "\n"), nil } commit, _, err := res.Request().Option("commit").Bool() @@ -59,7 +69,7 @@ var VersionCmd = &cmds.Command{ return nil, err } if commit { - commitTxt = "-" + v.Commit + commitTxt = "-" + version.Commit } number, _, err := res.Request().Option("number").Bool() @@ -67,7 +77,7 @@ var VersionCmd = &cmds.Command{ return nil, err } if number { - return strings.NewReader(fmt.Sprintln(v.Version + commitTxt)), nil + return strings.NewReader(fmt.Sprintln(version.Version + commitTxt)), nil } all, _, err := res.Request().Option("all").Bool() @@ -77,11 +87,11 @@ var VersionCmd = &cmds.Command{ if all { out := fmt.Sprintf("go-ipfs version: %s-%s\n"+ "Repo version: %s\nSystem version: %s\nGolang version: %s\n", - v.Version, v.Commit, v.Repo, v.System, v.Golang) + version.Version, version.Commit, version.Repo, version.System, version.Golang) return strings.NewReader(out), nil } - return strings.NewReader(fmt.Sprintf("ipfs version %s%s\n", v.Version, commitTxt)), nil + return strings.NewReader(fmt.Sprintf("ipfs version %s%s\n", version.Version, commitTxt)), nil }, }, Type: VersionOutput{}, diff --git a/core/core_test.go b/core/core_test.go index 58dd239de..d7b2c4453 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -4,6 +4,7 @@ import ( "testing" context "context" + "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" ds2 "github.com/ipfs/go-ipfs/thirdparty/datastore2" diff --git a/core/corehttp/commands.go b/core/corehttp/commands.go index 882121c4e..9f689e9f4 100644 --- a/core/corehttp/commands.go +++ b/core/corehttp/commands.go @@ -7,11 +7,12 @@ import ( "strconv" "strings" - commands "github.com/ipfs/go-ipfs/commands" - cmdsHttp "github.com/ipfs/go-ipfs/commands/http" core "github.com/ipfs/go-ipfs/core" corecommands "github.com/ipfs/go-ipfs/core/commands" config "github.com/ipfs/go-ipfs/repo/config" + + cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + cmdsHttp "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/http" ) const originEnvKey = "API_ORIGIN" @@ -99,7 +100,7 @@ func patchCORSVars(c *cmdsHttp.ServerConfig, addr net.Addr) { c.SetAllowedOrigins(origins...) } -func commandsOption(cctx commands.Context, command *commands.Command) ServeOption { +func commandsOption(cctx cmds.Context, command *cmds.Command) ServeOption { return func(n *core.IpfsNode, l net.Listener, mux *http.ServeMux) (*http.ServeMux, error) { cfg := cmdsHttp.NewServerConfig() @@ -120,10 +121,10 @@ func commandsOption(cctx commands.Context, command *commands.Command) ServeOptio } } -func CommandsOption(cctx commands.Context) ServeOption { +func CommandsOption(cctx cmds.Context) ServeOption { return commandsOption(cctx, corecommands.Root) } -func CommandsROOption(cctx commands.Context) ServeOption { +func CommandsROOption(cctx cmds.Context) ServeOption { return commandsOption(cctx, corecommands.RootRO) } diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index ce238fb4e..b46f6668d 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -8,6 +8,7 @@ import ( core "github.com/ipfs/go-ipfs/core" coreapi "github.com/ipfs/go-ipfs/core/coreapi" config "github.com/ipfs/go-ipfs/repo/config" + id "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/protocol/identify" ) diff --git a/core/coreunix/add.go b/core/coreunix/add.go index eca42b0a8..946275a67 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -12,7 +12,6 @@ import ( bs "github.com/ipfs/go-ipfs/blocks/blockstore" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" bserv "github.com/ipfs/go-ipfs/blockservice" - "github.com/ipfs/go-ipfs/commands/files" core "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/exchange/offline" balanced "github.com/ipfs/go-ipfs/importer/balanced" @@ -27,6 +26,7 @@ import ( cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" syncds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore/sync" diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go index add4395eb..68008c65f 100644 --- a/core/coreunix/add_test.go +++ b/core/coreunix/add_test.go @@ -12,7 +12,6 @@ import ( "github.com/ipfs/go-ipfs/blocks/blockstore" "github.com/ipfs/go-ipfs/blockservice" - "github.com/ipfs/go-ipfs/commands/files" "github.com/ipfs/go-ipfs/core" dag "github.com/ipfs/go-ipfs/merkledag" "github.com/ipfs/go-ipfs/pin/gc" @@ -23,6 +22,7 @@ import ( "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" ) func TestAddRecursive(t *testing.T) { diff --git a/core/coreunix/metadata_test.go b/core/coreunix/metadata_test.go index ddb22c751..ee07c764c 100644 --- a/core/coreunix/metadata_test.go +++ b/core/coreunix/metadata_test.go @@ -2,6 +2,7 @@ package coreunix import ( "bytes" + "context" "io/ioutil" "testing" @@ -15,7 +16,6 @@ import ( ft "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" - context "context" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" diff --git a/exchange/bitswap/bitswap_test.go b/exchange/bitswap/bitswap_test.go index d68858eef..e35461780 100644 --- a/exchange/bitswap/bitswap_test.go +++ b/exchange/bitswap/bitswap_test.go @@ -14,14 +14,14 @@ import ( tn "github.com/ipfs/go-ipfs/exchange/bitswap/testnet" mockrouting "github.com/ipfs/go-ipfs/routing/mock" delay "github.com/ipfs/go-ipfs/thirdparty/delay" - blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" - travis "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci/travis" detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - p2ptestutil "gx/ipfs/QmQGX417WoxKxDJeHqouMEmmH4G1RCENNSzkZYHrXy3Xb3/go-libp2p-netutil" tu "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" + travis "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci/travis" + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" + p2ptestutil "gx/ipfs/QmQGX417WoxKxDJeHqouMEmmH4G1RCENNSzkZYHrXy3Xb3/go-libp2p-netutil" ) // FIXME the tests are really sensitive to the network delay. fix them to work diff --git a/exchange/bitswap/decision/engine_test.go b/exchange/bitswap/decision/engine_test.go index 512548cf5..65ca05a71 100644 --- a/exchange/bitswap/decision/engine_test.go +++ b/exchange/bitswap/decision/engine_test.go @@ -1,6 +1,7 @@ package decision import ( + "context" "errors" "fmt" "math" @@ -8,7 +9,6 @@ import ( "sync" "testing" - context "context" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" message "github.com/ipfs/go-ipfs/exchange/bitswap/message" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" diff --git a/exchange/bitswap/message/message_test.go b/exchange/bitswap/message/message_test.go index 14233bf88..465953fbd 100644 --- a/exchange/bitswap/message/message_test.go +++ b/exchange/bitswap/message/message_test.go @@ -4,12 +4,12 @@ import ( "bytes" "testing" - proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto" - pb "github.com/ipfs/go-ipfs/exchange/bitswap/message/pb" + cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" + proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto" ) func mkFakeCid(s string) *cid.Cid { diff --git a/exchange/bitswap/message/pb/Makefile b/exchange/bitswap/message/pb/Makefile new file mode 100644 index 000000000..5bbebea07 --- /dev/null +++ b/exchange/bitswap/message/pb/Makefile @@ -0,0 +1,8 @@ +# TODO(brian): add proto tasks +all: message.pb.go + +message.pb.go: message.proto + protoc --gogo_out=. --proto_path=../../../../../:/usr/local/opt/protobuf/include:. $< + +clean: + rm message.pb.go diff --git a/exchange/bitswap/testnet/network_test.go b/exchange/bitswap/testnet/network_test.go index 803248552..5f14427ab 100644 --- a/exchange/bitswap/testnet/network_test.go +++ b/exchange/bitswap/testnet/network_test.go @@ -1,10 +1,10 @@ package bitswap import ( + "context" "sync" "testing" - context "context" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" mockrouting "github.com/ipfs/go-ipfs/routing/mock" diff --git a/exchange/bitswap/testnet/peernet.go b/exchange/bitswap/testnet/peernet.go index 32438508a..5aed6e24d 100644 --- a/exchange/bitswap/testnet/peernet.go +++ b/exchange/bitswap/testnet/peernet.go @@ -2,6 +2,7 @@ package bitswap import ( "context" + bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" mockrouting "github.com/ipfs/go-ipfs/routing/mock" ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" diff --git a/exchange/reprovide/reprovide_test.go b/exchange/reprovide/reprovide_test.go index ab4ed4afe..273c53ec0 100644 --- a/exchange/reprovide/reprovide_test.go +++ b/exchange/reprovide/reprovide_test.go @@ -1,9 +1,9 @@ package reprovide_test import ( + "context" "testing" - context "context" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" mock "github.com/ipfs/go-ipfs/routing/mock" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" diff --git a/fuse/ipns/common.go b/fuse/ipns/common.go index af6887b4e..d0d7ba247 100644 --- a/fuse/ipns/common.go +++ b/fuse/ipns/common.go @@ -1,7 +1,7 @@ package ipns import ( - context "context" + "context" "github.com/ipfs/go-ipfs/core" nsys "github.com/ipfs/go-ipfs/namesys" diff --git a/fuse/node/mount_test.go b/fuse/node/mount_test.go index 3e7583612..cceabb251 100644 --- a/fuse/node/mount_test.go +++ b/fuse/node/mount_test.go @@ -9,7 +9,8 @@ import ( "testing" "time" - context "context" + "context" + core "github.com/ipfs/go-ipfs/core" ipns "github.com/ipfs/go-ipfs/fuse/ipns" mount "github.com/ipfs/go-ipfs/fuse/mount" diff --git a/importer/balanced/balanced_test.go b/importer/balanced/balanced_test.go index 82b5f320f..22f091f73 100644 --- a/importer/balanced/balanced_test.go +++ b/importer/balanced/balanced_test.go @@ -2,6 +2,7 @@ package balanced import ( "bytes" + "context" "fmt" "io" "io/ioutil" @@ -14,7 +15,6 @@ import ( mdtest "github.com/ipfs/go-ipfs/merkledag/test" uio "github.com/ipfs/go-ipfs/unixfs/io" - "context" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" ) diff --git a/importer/chunk/rabin_test.go b/importer/chunk/rabin_test.go index ede2bc20a..9cef888ce 100644 --- a/importer/chunk/rabin_test.go +++ b/importer/chunk/rabin_test.go @@ -3,10 +3,11 @@ package chunk import ( "bytes" "fmt" - "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" - "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" "io" "testing" + + util "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" ) func TestRabinChunking(t *testing.T) { diff --git a/importer/helpers/dagbuilder.go b/importer/helpers/dagbuilder.go index 23a27e0cb..6384d1202 100644 --- a/importer/helpers/dagbuilder.go +++ b/importer/helpers/dagbuilder.go @@ -4,13 +4,13 @@ import ( "io" "os" - "github.com/ipfs/go-ipfs/commands/files" "github.com/ipfs/go-ipfs/importer/chunk" dag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" + files "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" ) // DagBuilderHelper wraps together a bunch of objects needed to diff --git a/importer/importer.go b/importer/importer.go index e10064e0a..43889583c 100644 --- a/importer/importer.go +++ b/importer/importer.go @@ -6,12 +6,12 @@ import ( "fmt" "os" - "github.com/ipfs/go-ipfs/commands/files" bal "github.com/ipfs/go-ipfs/importer/balanced" "github.com/ipfs/go-ipfs/importer/chunk" h "github.com/ipfs/go-ipfs/importer/helpers" trickle "github.com/ipfs/go-ipfs/importer/trickle" dag "github.com/ipfs/go-ipfs/merkledag" + "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" node "gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format" ) diff --git a/merkledag/utils/utils_test.go b/merkledag/utils/utils_test.go index 75d7181fc..0c3d77199 100644 --- a/merkledag/utils/utils_test.go +++ b/merkledag/utils/utils_test.go @@ -1,13 +1,13 @@ package dagutils import ( + "context" "testing" dag "github.com/ipfs/go-ipfs/merkledag" mdtest "github.com/ipfs/go-ipfs/merkledag/test" path "github.com/ipfs/go-ipfs/path" - context "context" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" ) diff --git a/mfs/repub_test.go b/mfs/repub_test.go index 1c21bd793..4a9bc4869 100644 --- a/mfs/repub_test.go +++ b/mfs/repub_test.go @@ -1,13 +1,12 @@ package mfs import ( + "context" "testing" "time" - ci "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci" - - "context" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" + ci "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci" ) func TestRepublisher(t *testing.T) { diff --git a/namesys/dns.go b/namesys/dns.go index 3cb2cd6e2..1267ef56b 100644 --- a/namesys/dns.go +++ b/namesys/dns.go @@ -7,7 +7,6 @@ import ( "strings" path "github.com/ipfs/go-ipfs/path" - isd "gx/ipfs/QmZmmuAXgX73UQmX1jRKjTGmjzq24Jinqkq8vzkBtno4uX/go-is-domain" ) diff --git a/namesys/interface.go b/namesys/interface.go index 84a6bbe2c..acaec1740 100644 --- a/namesys/interface.go +++ b/namesys/interface.go @@ -34,6 +34,7 @@ import ( "time" context "context" + path "github.com/ipfs/go-ipfs/path" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) diff --git a/namesys/ipns_select_test.go b/namesys/ipns_select_test.go index e12af16d9..9c0f34114 100644 --- a/namesys/ipns_select_test.go +++ b/namesys/ipns_select_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto" - pb "github.com/ipfs/go-ipfs/namesys/pb" path "github.com/ipfs/go-ipfs/path" + u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" + proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) diff --git a/namesys/proquint.go b/namesys/proquint.go index ee6ada978..3a842f97a 100644 --- a/namesys/proquint.go +++ b/namesys/proquint.go @@ -4,6 +4,7 @@ import ( "errors" context "context" + path "github.com/ipfs/go-ipfs/path" proquint "gx/ipfs/QmYnf27kzqR2cxt6LFZdrAFJuQd6785fTkBvMuEj9EeRxM/proquint" ) diff --git a/namesys/republisher/repub_test.go b/namesys/republisher/repub_test.go index be438b838..377b959ae 100644 --- a/namesys/republisher/repub_test.go +++ b/namesys/republisher/repub_test.go @@ -1,20 +1,20 @@ package republisher_test import ( + "context" "errors" "testing" "time" - context "context" - goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" - "github.com/ipfs/go-ipfs/core" mock "github.com/ipfs/go-ipfs/core/mock" namesys "github.com/ipfs/go-ipfs/namesys" . "github.com/ipfs/go-ipfs/namesys/republisher" path "github.com/ipfs/go-ipfs/path" + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock" + goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" ) func TestRepublish(t *testing.T) { diff --git a/package.json b/package.json index 6bb70baba..2dae65616 100644 --- a/package.json +++ b/package.json @@ -413,6 +413,16 @@ "name": "go-libp2p-swarm", "version": "2.0.5" }, + { + "hash": "QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe", + "name": "go-ipfs-cmds", + "version": "0.4.5" + }, + { + "hash": "QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf", + "name": "go-ipfs-cmdkit", + "version": "0.3.3" + }, { "author": "whyrusleeping", "hash": "QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU", diff --git a/repo/config/identity.go b/repo/config/identity.go index 077383c93..c440cc427 100644 --- a/repo/config/identity.go +++ b/repo/config/identity.go @@ -2,6 +2,7 @@ package config import ( "encoding/base64" + ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) diff --git a/routing/offline/offline_test.go b/routing/offline/offline_test.go index 9f5b3f0b2..253c533c0 100644 --- a/routing/offline/offline_test.go +++ b/routing/offline/offline_test.go @@ -3,9 +3,10 @@ package offline import ( "bytes" "context" - ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" - "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" "testing" + + "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" + ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" ) func TestOfflineRouterStorage(t *testing.T) { diff --git a/test/integration/addcat_test.go b/test/integration/addcat_test.go index 90fb177c6..75324dc90 100644 --- a/test/integration/addcat_test.go +++ b/test/integration/addcat_test.go @@ -2,6 +2,7 @@ package integrationtest import ( "bytes" + "context" "errors" "fmt" "io" @@ -10,13 +11,13 @@ import ( "testing" "time" - context "context" random "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-random" "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" "github.com/ipfs/go-ipfs/thirdparty/unit" + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" testutil "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" diff --git a/test/integration/bench_cat_test.go b/test/integration/bench_cat_test.go index 796194cea..53e539601 100644 --- a/test/integration/bench_cat_test.go +++ b/test/integration/bench_cat_test.go @@ -2,16 +2,17 @@ package integrationtest import ( "bytes" + "context" "errors" "io" "math" "testing" - context "context" "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" "github.com/ipfs/go-ipfs/thirdparty/unit" + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" testutil "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock" diff --git a/test/integration/bitswap_wo_routing_test.go b/test/integration/bitswap_wo_routing_test.go index dc0c656cd..f297e6f44 100644 --- a/test/integration/bitswap_wo_routing_test.go +++ b/test/integration/bitswap_wo_routing_test.go @@ -2,13 +2,13 @@ package integrationtest import ( "bytes" + "context" "testing" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/mock" "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" - context "context" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock" ) diff --git a/test/integration/three_legged_cat_test.go b/test/integration/three_legged_cat_test.go index 4fcf770e2..288115cd9 100644 --- a/test/integration/three_legged_cat_test.go +++ b/test/integration/three_legged_cat_test.go @@ -2,18 +2,18 @@ package integrationtest import ( "bytes" + "context" "errors" "io" "math" "testing" "time" - context "context" - core "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" "github.com/ipfs/go-ipfs/thirdparty/unit" + pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" testutil "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock" From 0d9d21875c21e71f485605976490c90b5f723866 Mon Sep 17 00:00:00 2001 From: keks Date: Mon, 23 Oct 2017 16:50:39 +0200 Subject: [PATCH 2/3] compatible to js-ipfs-api License: MIT Signed-off-by: keks --- cmd/ipfs/daemon.go | 2 +- cmd/ipfs/ipfs.go | 2 +- cmd/ipfs/main.go | 6 +++--- cmd/ipfswatch/main.go | 2 +- core/commands/add.go | 2 +- core/commands/bitswap.go | 6 ++++-- core/commands/block.go | 6 +++--- core/commands/cat.go | 2 +- core/commands/commands.go | 2 +- core/commands/config.go | 3 ++- core/commands/files/files.go | 3 +++ core/commands/filestore.go | 2 +- core/commands/get.go | 2 +- core/commands/helptext_test.go | 2 +- core/commands/pubsub.go | 4 ++-- core/commands/repo.go | 4 ++-- core/commands/root.go | 2 +- core/commands/stat.go | 2 +- core/corehttp/commands.go | 4 ++-- exchange/bitswap/bitswap_test.go | 4 ++-- namesys/republisher/repub_test.go | 2 +- package.json | 4 ++-- routing/offline/offline_test.go | 4 ++-- test/sharness/t0600-issues-and-regressions-online.sh | 2 +- 24 files changed, 40 insertions(+), 34 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index ec5fb775a..90f13f05b 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -19,9 +19,9 @@ import ( fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" migrate "github.com/ipfs/go-ipfs/repo/fsrepo/migrations" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" mprome "gx/ipfs/QmSk46nSD78YiuNojYMS8NW6hSCjH95JajqqzzoychZgef/go-metrics-prometheus" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" "gx/ipfs/QmX3QZ5jHEPidwUrymXV1iSCSUhdGxj15sm2gP4jKMef7B/client_golang/prometheus" "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net" ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go index db4768610..c37080898 100644 --- a/cmd/ipfs/ipfs.go +++ b/cmd/ipfs/ipfs.go @@ -6,7 +6,7 @@ import ( oldcmds "github.com/ipfs/go-ipfs/commands" commands "github.com/ipfs/go-ipfs/core/commands" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) // This is the CLI root, used for executing commands accessible to CLI clients. diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index acdb0ecb5..9c6062597 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -25,13 +25,13 @@ import ( config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/cli" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/http" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" loggables "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds/cli" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds/http" manet "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net" ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" osh "gx/ipfs/QmXuBJ7DR6k3rmUEKtvVMhwjmXDuJgXXPUt4LQXKBMsU93/go-os-helper" diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index 6d34d3a14..e0423e93d 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -17,8 +17,8 @@ import ( homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - commands "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" process "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" + commands "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" fsnotify "gx/ipfs/QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv/fsnotify.v1" ) diff --git a/core/commands/add.go b/core/commands/add.go index 5ac2de87f..d2bf86888 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -17,10 +17,10 @@ import ( mfs "github.com/ipfs/go-ipfs/mfs" ft "github.com/ipfs/go-ipfs/unixfs" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" ) diff --git a/core/commands/bitswap.go b/core/commands/bitswap.go index 1faca19c3..c4390f668 100644 --- a/core/commands/bitswap.go +++ b/core/commands/bitswap.go @@ -12,8 +12,8 @@ import ( cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ) @@ -75,6 +75,8 @@ var unwantCmd = &oldcmds.Command{ // messing with the internal state of bitswap. You should cancel wants // by killing the command that caused the want. bs.CancelWants(ks, 0) + + res.SetOutput(nil) }, } @@ -162,7 +164,7 @@ var bitswapStatCmd = &cmds.Command{ return } - res.Emit(st) + cmds.EmitOnce(res, st) }, Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error { diff --git a/core/commands/block.go b/core/commands/block.go index fdc1ac9c8..1e910636a 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -9,8 +9,8 @@ import ( util "github.com/ipfs/go-ipfs/blocks/blockstore/util" e "github.com/ipfs/go-ipfs/core/commands/e" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" @@ -67,7 +67,7 @@ on raw IPFS blocks. It outputs the following to stdout: return } - err = res.Emit(&BlockStat{ + err = cmds.EmitOnce(res, &BlockStat{ Key: b.Cid().String(), Size: len(b.RawData()), }) @@ -204,7 +204,7 @@ It reads from stdin, and is a base58 encoded multihash. return } - err = res.Emit(&BlockStat{ + err = cmds.EmitOnce(res, &BlockStat{ Key: k.String(), Size: len(data), }) diff --git a/core/commands/cat.go b/core/commands/cat.go index 80247629b..e0ff5f444 100644 --- a/core/commands/cat.go +++ b/core/commands/cat.go @@ -8,8 +8,8 @@ import ( core "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB diff --git a/core/commands/commands.go b/core/commands/commands.go index f91e263f3..8f18c2470 100644 --- a/core/commands/commands.go +++ b/core/commands/commands.go @@ -14,8 +14,8 @@ import ( oldcmds "github.com/ipfs/go-ipfs/commands" e "github.com/ipfs/go-ipfs/core/commands/e" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) type commandEncoder struct { diff --git a/core/commands/config.go b/core/commands/config.go index 36926a9f0..6c91ba24a 100644 --- a/core/commands/config.go +++ b/core/commands/config.go @@ -155,7 +155,8 @@ included in the output of this command. }, Run: func(req cmds.Request, res cmds.Response) { - fname, err := config.Filename(req.InvocContext().ConfigRoot) + cfgPath := req.InvocContext().ConfigRoot + fname, err := config.Filename(cfgPath) if err != nil { res.SetError(err, cmdkit.ErrNormal) return diff --git a/core/commands/files/files.go b/core/commands/files/files.go index ee265e4dc..5a3c10ad5 100644 --- a/core/commands/files/files.go +++ b/core/commands/files/files.go @@ -794,6 +794,7 @@ Examples: res.SetError(err, cmdkit.ErrNormal) return } + res.SetOutput(nil) }, } @@ -870,6 +871,8 @@ Change the cid version or hash function of the root node of a given path. res.SetError(err, cmdkit.ErrNormal) return } + + res.SetOutput(nil) }, } diff --git a/core/commands/filestore.go b/core/commands/filestore.go index 79ea730d2..0b6bdafbe 100644 --- a/core/commands/filestore.go +++ b/core/commands/filestore.go @@ -12,8 +12,8 @@ import ( "github.com/ipfs/go-ipfs/filestore" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) var FileStoreCmd = &cmds.Command{ diff --git a/core/commands/get.go b/core/commands/get.go index be2f31582..be6abbd7a 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -16,8 +16,8 @@ import ( tar "github.com/ipfs/go-ipfs/thirdparty/tar" uarchive "github.com/ipfs/go-ipfs/unixfs/archive" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" ) diff --git a/core/commands/helptext_test.go b/core/commands/helptext_test.go index 3b10b4702..9120a3200 100644 --- a/core/commands/helptext_test.go +++ b/core/commands/helptext_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) { diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index c0ecbca3e..62f9d7c4c 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -12,10 +12,10 @@ import ( cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" - floodsub "gx/ipfs/QmUUSLfvihARhCxxgnjW4hmycJpPvzNu12Aaz6JWVdfnLg/go-libp2p-floodsub" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" + floodsub "gx/ipfs/QmUUSLfvihARhCxxgnjW4hmycJpPvzNu12Aaz6JWVdfnLg/go-libp2p-floodsub" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) var PubsubCmd = &cmds.Command{ diff --git a/core/commands/repo.go b/core/commands/repo.go index 7d764cab1..9ef9a47c9 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -18,8 +18,8 @@ import ( lockfile "github.com/ipfs/go-ipfs/repo/fsrepo/lock" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) type RepoVersion struct { @@ -162,7 +162,7 @@ Version string The repo version. return } - res.Emit(stat) + cmds.EmitOnce(res, stat) }, Options: []cmdkit.Option{ cmdkit.BoolOption("human", "Output RepoSize in MiB.").Default(false), diff --git a/core/commands/root.go b/core/commands/root.go index 09f233728..627886ab3 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -11,9 +11,9 @@ import ( ocmd "github.com/ipfs/go-ipfs/core/commands/object" unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs" - "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" + "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" ) var log = logging.Logger("core/commands") diff --git a/core/commands/stat.go b/core/commands/stat.go index b41bf56cc..05632dc4e 100644 --- a/core/commands/stat.go +++ b/core/commands/stat.go @@ -8,9 +8,9 @@ import ( "time" humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" metrics "gx/ipfs/QmQbh3Rb7KM37As3vkHYnEFnzkVXNCP8EYGtHz6g2fXk14/go-libp2p-metrics" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol" ) diff --git a/core/corehttp/commands.go b/core/corehttp/commands.go index 9f689e9f4..3910076f3 100644 --- a/core/corehttp/commands.go +++ b/core/corehttp/commands.go @@ -11,8 +11,8 @@ import ( corecommands "github.com/ipfs/go-ipfs/core/commands" config "github.com/ipfs/go-ipfs/repo/config" - cmds "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds" - cmdsHttp "gx/ipfs/QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe/go-ipfs-cmds/http" + cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmdsHttp "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds/http" ) const originEnvKey = "API_ORIGIN" diff --git a/exchange/bitswap/bitswap_test.go b/exchange/bitswap/bitswap_test.go index e35461780..5abc37527 100644 --- a/exchange/bitswap/bitswap_test.go +++ b/exchange/bitswap/bitswap_test.go @@ -18,10 +18,10 @@ import ( detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" + p2ptestutil "gx/ipfs/QmQGX417WoxKxDJeHqouMEmmH4G1RCENNSzkZYHrXy3Xb3/go-libp2p-netutil" + blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" tu "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" travis "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci/travis" - blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" - p2ptestutil "gx/ipfs/QmQGX417WoxKxDJeHqouMEmmH4G1RCENNSzkZYHrXy3Xb3/go-libp2p-netutil" ) // FIXME the tests are really sensitive to the network delay. fix them to work diff --git a/namesys/republisher/repub_test.go b/namesys/republisher/repub_test.go index 377b959ae..7586b2f6c 100644 --- a/namesys/republisher/repub_test.go +++ b/namesys/republisher/repub_test.go @@ -13,8 +13,8 @@ import ( path "github.com/ipfs/go-ipfs/path" pstore "gx/ipfs/QmPgDWmTmuzvP7QE5zwo1TmjbJme9pmZHNujB2453jkCTr/go-libp2p-peerstore" - mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock" goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" + mocknet "gx/ipfs/QmefgzMbKZYsmHFkLqxgaTBG9ypeEjrdWRD5WXH4j1cWDL/go-libp2p/p2p/net/mock" ) func TestRepublish(t *testing.T) { diff --git a/package.json b/package.json index 2dae65616..b2d6a444e 100644 --- a/package.json +++ b/package.json @@ -414,9 +414,9 @@ "version": "2.0.5" }, { - "hash": "QmQVvuDwXUGbtYmbmTcbLtGRYXnEbymaR2zEj38GVysqWe", + "hash": "QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R", "name": "go-ipfs-cmds", - "version": "0.4.5" + "version": "0.4.7" }, { "hash": "QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf", diff --git a/routing/offline/offline_test.go b/routing/offline/offline_test.go index 253c533c0..5c00bc3c1 100644 --- a/routing/offline/offline_test.go +++ b/routing/offline/offline_test.go @@ -4,9 +4,9 @@ import ( "bytes" "context" "testing" - - "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" + ds "gx/ipfs/QmVSase1JP7cq9QkPT46oNwdp9pT6kBkG3oqS14y3QcZjG/go-datastore" + "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil" ) func TestOfflineRouterStorage(t *testing.T) { diff --git a/test/sharness/t0600-issues-and-regressions-online.sh b/test/sharness/t0600-issues-and-regressions-online.sh index e49d8c663..132f59721 100755 --- a/test/sharness/t0600-issues-and-regressions-online.sh +++ b/test/sharness/t0600-issues-and-regressions-online.sh @@ -48,7 +48,7 @@ test_expect_success "pin add api looks right - #3753" ' test_expect_success "no daemon crash on improper file argument - #4003" ' FNC=$(echo $API_ADDR | awk -F: '\''{ printf "%s %s", $1, $2 }'\'') && - printf "POST /api/v0/add?pin=true HTTP/1.1\r\nHost: $API_ADDR\r\nContent-Type: multipart/form-data; boundary=Pyw9xQLtiLPE6XcI\r\nContent-Length: 22\r\n\r\n\r\n--Pyw9xQLtiLPE6XcI\r\n" | nc -v $FNC | grep -m1 "200 OK" + printf "POST /api/v0/add?pin=true HTTP/1.1\r\nHost: $API_ADDR\r\nContent-Type: multipart/form-data; boundary=Pyw9xQLtiLPE6XcI\r\nContent-Length: 22\r\n\r\n\r\n--Pyw9xQLtiLPE6XcI\r\n" | nc -v $FNC | grep -m1 "500 Internal Server Error" ' test_kill_ipfs_daemon From d95a87cf5793138e653aab4ded394781fe6a4874 Mon Sep 17 00:00:00 2001 From: keks Date: Thu, 26 Oct 2017 13:19:27 +0200 Subject: [PATCH 3/3] update to go-ipfs-cmds 0.4.9 License: MIT Signed-off-by: keks --- cmd/ipfs/daemon.go | 2 +- cmd/ipfs/ipfs.go | 2 +- cmd/ipfs/main.go | 6 +++--- cmd/ipfswatch/main.go | 2 +- core/commands/add.go | 2 +- core/commands/bitswap.go | 2 +- core/commands/block.go | 2 +- core/commands/cat.go | 2 +- core/commands/commands.go | 2 +- core/commands/filestore.go | 2 +- core/commands/get.go | 2 +- core/commands/helptext_test.go | 2 +- core/commands/pubsub.go | 2 +- core/commands/repo.go | 2 +- core/commands/root.go | 2 +- core/commands/stat.go | 2 +- core/corehttp/commands.go | 4 ++-- package.json | 4 ++-- 18 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 90f13f05b..519a69bd4 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -21,7 +21,7 @@ import ( "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" mprome "gx/ipfs/QmSk46nSD78YiuNojYMS8NW6hSCjH95JajqqzzoychZgef/go-metrics-prometheus" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" "gx/ipfs/QmX3QZ5jHEPidwUrymXV1iSCSUhdGxj15sm2gP4jKMef7B/client_golang/prometheus" "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net" ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" diff --git a/cmd/ipfs/ipfs.go b/cmd/ipfs/ipfs.go index c37080898..71bc4f527 100644 --- a/cmd/ipfs/ipfs.go +++ b/cmd/ipfs/ipfs.go @@ -6,7 +6,7 @@ import ( oldcmds "github.com/ipfs/go-ipfs/commands" commands "github.com/ipfs/go-ipfs/core/commands" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) // This is the CLI root, used for executing commands accessible to CLI clients. diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 9c6062597..5ce375b6d 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -29,9 +29,9 @@ import ( u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" loggables "gx/ipfs/QmT4PgCNdv73hnFAqzHqwW44q7M9PWpykSswHDxndquZbc/go-libp2p-loggables" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds/cli" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds/http" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds/cli" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds/http" manet "gx/ipfs/QmX3U3YXCQ6UYBxq2LVWF8dARS1hPUTEYLrSx654Qyxyw6/go-multiaddr-net" ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr" osh "gx/ipfs/QmXuBJ7DR6k3rmUEKtvVMhwjmXDuJgXXPUt4LQXKBMsU93/go-os-helper" diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index e0423e93d..510a38c54 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -18,7 +18,7 @@ import ( homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" process "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" - commands "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + commands "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" fsnotify "gx/ipfs/QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv/fsnotify.v1" ) diff --git a/core/commands/add.go b/core/commands/add.go index d2bf86888..d54291687 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -20,7 +20,7 @@ import ( "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files" mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" ) diff --git a/core/commands/bitswap.go b/core/commands/bitswap.go index c4390f668..06f53536e 100644 --- a/core/commands/bitswap.go +++ b/core/commands/bitswap.go @@ -13,7 +13,7 @@ import ( cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ) diff --git a/core/commands/block.go b/core/commands/block.go index 1e910636a..09a595ec7 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -10,7 +10,7 @@ import ( util "github.com/ipfs/go-ipfs/blocks/blockstore/util" e "github.com/ipfs/go-ipfs/core/commands/e" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" diff --git a/core/commands/cat.go b/core/commands/cat.go index e0ff5f444..3a978a796 100644 --- a/core/commands/cat.go +++ b/core/commands/cat.go @@ -9,7 +9,7 @@ import ( coreunix "github.com/ipfs/go-ipfs/core/coreunix" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB diff --git a/core/commands/commands.go b/core/commands/commands.go index 8f18c2470..49ee4cff1 100644 --- a/core/commands/commands.go +++ b/core/commands/commands.go @@ -15,7 +15,7 @@ import ( e "github.com/ipfs/go-ipfs/core/commands/e" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) type commandEncoder struct { diff --git a/core/commands/filestore.go b/core/commands/filestore.go index 0b6bdafbe..e5a60608f 100644 --- a/core/commands/filestore.go +++ b/core/commands/filestore.go @@ -13,7 +13,7 @@ import ( cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) var FileStoreCmd = &cmds.Command{ diff --git a/core/commands/get.go b/core/commands/get.go index be6abbd7a..ec70ab66b 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -17,7 +17,7 @@ import ( uarchive "github.com/ipfs/go-ipfs/unixfs/archive" "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" "gx/ipfs/QmeWjRodbcZFKe5tMN7poEx3izym6osrLSnTLf9UjJZBbs/pb" ) diff --git a/core/commands/helptext_test.go b/core/commands/helptext_test.go index 9120a3200..a07c3760c 100644 --- a/core/commands/helptext_test.go +++ b/core/commands/helptext_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) { diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index 62f9d7c4c..664c3cebb 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -15,7 +15,7 @@ import ( cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format" floodsub "gx/ipfs/QmUUSLfvihARhCxxgnjW4hmycJpPvzNu12Aaz6JWVdfnLg/go-libp2p-floodsub" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) var PubsubCmd = &cmds.Command{ diff --git a/core/commands/repo.go b/core/commands/repo.go index 9ef9a47c9..d8de28e95 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -19,7 +19,7 @@ import ( cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) type RepoVersion struct { diff --git a/core/commands/root.go b/core/commands/root.go index 627886ab3..e3de7c99d 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -13,7 +13,7 @@ import ( "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" - "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" ) var log = logging.Logger("core/commands") diff --git a/core/commands/stat.go b/core/commands/stat.go index 05632dc4e..3fd48214b 100644 --- a/core/commands/stat.go +++ b/core/commands/stat.go @@ -10,7 +10,7 @@ import ( humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize" metrics "gx/ipfs/QmQbh3Rb7KM37As3vkHYnEFnzkVXNCP8EYGtHz6g2fXk14/go-libp2p-metrics" cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol" ) diff --git a/core/corehttp/commands.go b/core/corehttp/commands.go index 3910076f3..7874733fc 100644 --- a/core/corehttp/commands.go +++ b/core/corehttp/commands.go @@ -11,8 +11,8 @@ import ( corecommands "github.com/ipfs/go-ipfs/core/commands" config "github.com/ipfs/go-ipfs/repo/config" - cmds "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds" - cmdsHttp "gx/ipfs/QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R/go-ipfs-cmds/http" + cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds" + cmdsHttp "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds/http" ) const originEnvKey = "API_ORIGIN" diff --git a/package.json b/package.json index b2d6a444e..12348d92e 100644 --- a/package.json +++ b/package.json @@ -414,9 +414,9 @@ "version": "2.0.5" }, { - "hash": "QmUsuV7rMitqBCk2UPmX1f3Vtp4tJNi6xvXpkQgKujjW5R", + "hash": "QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k", "name": "go-ipfs-cmds", - "version": "0.4.7" + "version": "0.4.9" }, { "hash": "QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf",