mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 10:27:46 +08:00
Merge pull request #3856 from ipfs/feat/commands2.0
Extract and rework commands package
This commit is contained in:
commit
83df6769ac
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
context "context"
|
||||
|
||||
"gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
|
||||
)
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
},
|
||||
|
||||
@ -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},
|
||||
}
|
||||
|
||||
153
cmd/ipfs/main.go
153
cmd/ipfs/main.go
@ -18,9 +18,6 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs/commands"
|
||||
cmdsCli "github.com/ipfs/go-ipfs/commands/cli"
|
||||
cmdsHttp "github.com/ipfs/go-ipfs/commands/http"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
coreCmds "github.com/ipfs/go-ipfs/core/commands"
|
||||
"github.com/ipfs/go-ipfs/plugin/loader"
|
||||
@ -28,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 {
|
||||
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
)
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
package commands
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type ChannelMarshaler struct {
|
||||
Channel <-chan interface{}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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",
|
||||
},
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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{}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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{},
|
||||
}
|
||||
|
||||
@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
@ -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{},
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
},
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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{},
|
||||
}
|
||||
|
||||
@ -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.",
|
||||
},
|
||||
|
||||
|
||||
@ -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
30
core/commands/e/error.go
Normal 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()}
|
||||
}
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
},
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
},
|
||||
},
|
||||
|
||||
@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
},
|
||||
},
|
||||
|
||||
@ -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],
|
||||
},
|
||||
}
|
||||
|
||||
@ -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
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
},
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
@ -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
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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{},
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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"
|
||||
)
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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 {
|
||||
|
||||
8
exchange/bitswap/message/pb/Makefile
Normal file
8
exchange/bitswap/message/pb/Makefile
Normal 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
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
Loading…
Reference in New Issue
Block a user