Merge pull request #3856 from ipfs/feat/commands2.0

Extract and rework commands package
This commit is contained in:
Whyrusleeping 2017-11-18 10:10:50 -08:00 committed by GitHub
commit 83df6769ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 2933 additions and 3347 deletions

View File

@ -4,6 +4,7 @@ import (
"errors"
context "context"
"gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
)

View File

@ -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)

View File

@ -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,7 +19,9 @@ import (
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
migrate "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
"gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
mprome "gx/ipfs/QmSk46nSD78YiuNojYMS8NW6hSCjH95JajqqzzoychZgef/go-metrics-prometheus"
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"
@ -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)
}
}
}

View File

@ -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
}
},

View File

@ -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/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/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},
}

View File

@ -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,9 +25,13 @@ import (
config "github.com/ipfs/go-ipfs/repo/config"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
"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/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"
@ -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 {

View File

@ -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")
}
}

View File

@ -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"
@ -19,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/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
fsnotify "gx/ipfs/QmczzCMvJ3HV57WBKDy8b4ucp7quT325JjDbixYRS5Pwvv/fsnotify.v1"
)

View File

@ -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"

View File

@ -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
}

View File

@ -1,6 +1,8 @@
package commands
import "io"
import (
"io"
)
type ChannelMarshaler struct {
Channel <-chan interface{}

View File

@ -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
}

View File

@ -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 {

View File

@ -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",
},

View File

@ -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 <file> means disregard <file> 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)
}
}

View File

@ -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(),
},
},
},

View File

@ -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 <cmd usage>
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,
}

View File

@ -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{

View File

@ -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
}

View File

@ -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")
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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, "<<default>>") {
return strings.Replace(o.description, "<<default>>",
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,
}

View File

@ -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")
}
}

View File

@ -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()
}

View File

@ -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{}

View File

@ -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
}

View File

@ -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")
}
}

View File

@ -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"

View File

@ -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
}

View File

@ -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/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
"gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit/files"
mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash"
"gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
"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 <path> 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{},
}

View File

@ -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"
cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
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
}
@ -70,46 +75,48 @@ var unwantCmd = &cmds.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)
},
}
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 +129,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)
cmds.EmitOnce(res, 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 +204,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 +258,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)
},
}

View File

@ -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/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
"gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
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 = cmds.EmitOnce(res, &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 <key> 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 <key> 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 <key> 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 <key> 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 = cmds.EmitOnce(res, &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{},

View File

@ -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 '<multiaddr>/<peerID>')"
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 '<multiaddr>/<peerID>'.",
},
@ -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
}

View File

@ -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"
"gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
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
},
},
}

View File

@ -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"
"gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
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
}

View File

@ -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
@ -144,34 +155,35 @@ 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, 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 +233,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 +244,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 <file>.",
ShortDescription: `
Make sure to back up the config file first if necessary, as this operation
@ -252,27 +264,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
}
},

View File

@ -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
}

View File

@ -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{},
}

View File

@ -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.",
},

View File

@ -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
},

30
core/commands/e/error.go Normal file
View File

@ -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()}
}

View File

@ -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()

View File

@ -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: "+
"<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").Default(
`<hash>
Size: <size>
CumulativeSize: <cumulsize>
ChildBlocks: <childs>
Type: <type>`),
cmds.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options.").Default(false),
cmds.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options.").Default(false),
cmdkit.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options.").Default(false),
cmdkit.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. 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: <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,29 @@ 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 +824,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,15 +862,17 @@ 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
}
res.SetOutput(nil)
},
}
@ -874,7 +901,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 +915,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 +949,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 +966,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 +976,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 +986,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 +1103,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
}

View File

@ -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"
"gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
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:
<hash> <size> <path> <offset>
`,
},
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)

View File

@ -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/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
"gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
"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
},
},
}

View File

@ -4,7 +4,7 @@ import (
"strings"
"testing"
cmds "github.com/ipfs/go-ipfs/commands"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) {

View File

@ -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="<addrs>\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()

View File

@ -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
},

View File

@ -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)

View File

@ -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.

View File

@ -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 {

View File

@ -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

View File

@ -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
},
},

View File

@ -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)
},
}

View File

@ -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

View File

@ -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 {

View File

@ -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 <key>.",
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 <key>.",
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
}

View File

@ -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 <root> <cmd> <args>' 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
}

View File

@ -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
}
}

View File

@ -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{

View File

@ -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),

View File

@ -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 <ipfs-path> 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. <<default>>
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>>.").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>>.").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 <ipfs-path> 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 <ipfs-path> 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 <ipfs-path> 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
},
},

View File

@ -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"
cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
floodsub "gx/ipfs/QmUUSLfvihARhCxxgnjW4hmycJpPvzNu12Aaz6JWVdfnLg/go-libp2p-floodsub"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
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],
},
}

View File

@ -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: <src> <dst> <linkname>.").Default("<dst>"),
cmds.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`.").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: <src> <dst> <linkname>.").Default("<dst>"),
cmdkit.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`.").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 != "<dst>" {
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
},
}

View File

@ -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"
cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
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)
cmds.EmitOnce(res, 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 {

View File

@ -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
},

View File

@ -4,12 +4,16 @@ 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/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
"gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
)
var log = logging.Logger("core/commands")
@ -19,7 +23,7 @@ const (
)
var Root = &cmds.Command{
Helptext: cmds.HelpText{
Helptext: cmdkit.HelpText{
Tagline: "Global p2p merkle-dag filesystem.",
Synopsis: "ipfs [--config=<config> | -c] [--debug=<debug> | -D] [--help=<help>] [-h=<h>] [--local=<local> | -L] [--api=<api>] <command> ...",
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
}

View File

@ -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)
},
}

View File

@ -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"
metrics "gx/ipfs/QmQbh3Rb7KM37As3vkHYnEFnzkVXNCP8EYGtHz6g2fXk14/go-libp2p-metrics"
u "gx/ipfs/QmSU6eubNdhXjFBJBSksTp8kv8YRub8mGAPv8tVJHmL2EU/go-ipfs-util"
cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
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
},
},
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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{},

View File

@ -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"

View File

@ -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/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
cmdsHttp "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/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)
}

View File

@ -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"
)

View File

@ -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"

View File

@ -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) {

View File

@ -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"

View File

@ -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"
blocks "gx/ipfs/QmSn9Td7xgxm9EV7iEjTckpUWmWApggzPxu7eFGWkkpwin/go-block-format"
tu "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil"
travis "gx/ipfs/QmWRCn8vruNAzHx8i6SAXinuheRitKEGu8c7m26stKvsYx/go-testutil/ci/travis"
)
// FIXME the tests are really sensitive to the network delay. fix them to work

View File

@ -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"

View File

@ -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 {

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -1,7 +1,7 @@
package ipns
import (
context "context"
"context"
"github.com/ipfs/go-ipfs/core"
nsys "github.com/ipfs/go-ipfs/namesys"

Some files were not shown because too many files have changed in this diff Show More