Merge pull request #5665 from overbool/refactor/commands/files

commands/files: use new cmds
This commit is contained in:
Steven Allen 2018-11-02 10:57:14 -07:00 committed by GitHub
commit f337acd895
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,7 +1,6 @@
package commands
import (
"bytes"
"context"
"errors"
"fmt"
@ -11,12 +10,9 @@ import (
"sort"
"strings"
oldcmds "github.com/ipfs/go-ipfs/commands"
lgc "github.com/ipfs/go-ipfs/commands/legacy"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
iface "github.com/ipfs/go-ipfs/core/coreapi/interface"
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
@ -53,19 +49,19 @@ operations.
`,
},
Options: []cmdkit.Option{
cmdkit.BoolOption("f", "flush", "Flush target and ancestors after write.").WithDefault(true),
cmdkit.BoolOption(filesFlushOptionName, "f", "Flush target and ancestors after write.").WithDefault(true),
},
Subcommands: map[string]*cmds.Command{
"read": lgc.NewCommand(filesReadCmd),
"read": filesReadCmd,
"write": filesWriteCmd,
"mv": lgc.NewCommand(filesMvCmd),
"cp": lgc.NewCommand(filesCpCmd),
"ls": lgc.NewCommand(filesLsCmd),
"mkdir": lgc.NewCommand(filesMkdirCmd),
"mv": filesMvCmd,
"cp": filesCpCmd,
"ls": filesLsCmd,
"mkdir": filesMkdirCmd,
"stat": filesStatCmd,
"rm": lgc.NewCommand(filesRmCmd),
"flush": lgc.NewCommand(filesFlushCmd),
"chcid": lgc.NewCommand(filesChcidCmd),
"rm": filesRmCmd,
"flush": filesFlushCmd,
"chcid": filesChcidCmd,
},
}
@ -174,12 +170,7 @@ var filesStatCmd = &cmds.Command{
return cmds.EmitOnce(res, o)
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
out, ok := v.(*statOutput)
if !ok {
return e.TypeErr(out, v)
}
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *statOutput) error {
s, _ := statGetFormatOptions(req)
s = strings.Replace(s, "<hash>", out.Hash, -1)
s = strings.Replace(s, "<size>", fmt.Sprintf("%d", out.Size), -1)
@ -303,7 +294,7 @@ func walkBlock(ctx context.Context, dagserv ipld.DAGService, nd ipld.Node) (bool
return local, sizeLocal, nil
}
var filesCpCmd = &oldcmds.Command{
var filesCpCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Copy files into mfs.",
},
@ -311,59 +302,52 @@ var filesCpCmd = &oldcmds.Command{
cmdkit.StringArg("source", true, false, "Source object to copy."),
cmdkit.StringArg("dest", true, false, "Destination to copy object to."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
node, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
api, err := req.InvocContext().GetApi()
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
flush, _, _ := req.Option("flush").Bool()
flush, _ := req.Options[filesFlushOptionName].(bool)
src, err := checkPath(req.Arguments()[0])
src, err := checkPath(req.Arguments[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
src = strings.TrimRight(src, "/")
dst, err := checkPath(req.Arguments()[1])
dst, err := checkPath(req.Arguments[1])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if dst[len(dst)-1] == '/' {
dst += gopath.Base(src)
}
nd, err := getNodeFromPath(req.Context(), node, api, src)
node, err := getNodeFromPath(req.Context, nd, api, src)
if err != nil {
res.SetError(fmt.Errorf("cp: cannot get node from path %s: %s", src, err), cmdkit.ErrNormal)
return
return fmt.Errorf("cp: cannot get node from path %s: %s", src, err)
}
err = mfs.PutNode(node.FilesRoot, dst, nd)
err = mfs.PutNode(nd.FilesRoot, dst, node)
if err != nil {
res.SetError(fmt.Errorf("cp: cannot put node in path %s: %s", dst, err), cmdkit.ErrNormal)
return
return fmt.Errorf("cp: cannot put node in path %s: %s", dst, err)
}
if flush {
err := mfs.FlushPath(node.FilesRoot, dst)
err := mfs.FlushPath(nd.FilesRoot, dst)
if err != nil {
res.SetError(fmt.Errorf("cp: cannot flush the created file %s: %s", dst, err), cmdkit.ErrNormal)
return
return fmt.Errorf("cp: cannot flush the created file %s: %s", dst, err)
}
}
res.SetOutput(nil)
return nil
},
}
@ -395,7 +379,7 @@ const (
dontSortOptionName = "U"
)
var filesLsCmd = &oldcmds.Command{
var filesLsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List directories in the local mutable namespace.",
ShortDescription: `
@ -423,43 +407,39 @@ Examples:
cmdkit.BoolOption(longOptionName, "Use long listing format."),
cmdkit.BoolOption(dontSortOptionName, "Do not sort; list entries in directory order."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
var arg string
if len(req.Arguments()) == 0 {
if len(req.Arguments) == 0 {
arg = "/"
} else {
arg = req.Arguments()[0]
arg = req.Arguments[0]
}
path, err := checkPath(arg)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
nd, err := req.InvocContext().GetNode()
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
fsn, err := mfs.Lookup(nd.FilesRoot, path)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
long, _, _ := req.Option(longOptionName).Bool()
long, _ := req.Options[longOptionName].(bool)
switch fsn := fsn.(type) {
case *mfs.Directory:
if !long {
var output []mfs.NodeListing
names, err := fsn.ListNames(req.Context())
names, err := fsn.ListNames(req.Context)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
for _, name := range names {
@ -467,16 +447,13 @@ Examples:
Name: name,
})
}
res.SetOutput(&filesLsOutput{output})
} else {
listing, err := fsn.List(req.Context())
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
res.SetOutput(&filesLsOutput{listing})
return cmds.EmitOnce(res, &filesLsOutput{output})
}
return
listing, err := fsn.List(req.Context)
if err != nil {
return err
}
return cmds.EmitOnce(res, &filesLsOutput{listing})
case *mfs.File:
_, name := gopath.Split(path)
out := &filesLsOutput{[]mfs.NodeListing{{Name: name}}}
@ -485,58 +462,44 @@ Examples:
size, err := fsn.Size()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
out.Entries[0].Size = size
nd, err := fsn.GetNode()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
out.Entries[0].Hash = nd.Cid().String()
}
res.SetOutput(out)
return
return cmds.EmitOnce(res, out)
default:
res.SetError(errors.New("unrecognized type"), cmdkit.ErrNormal)
return errors.New("unrecognized type")
}
},
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.(*filesLsOutput)
if !ok {
return nil, e.TypeErr(out, v)
}
buf := new(bytes.Buffer)
noSort, _, _ := res.Request().Option(dontSortOptionName).Bool()
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *filesLsOutput) error {
noSort, _ := req.Options[dontSortOptionName].(bool)
if !noSort {
sort.Slice(out.Entries, func(i, j int) bool {
return strings.Compare(out.Entries[i].Name, out.Entries[j].Name) < 0
})
}
long, _, _ := res.Request().Option(longOptionName).Bool()
long, _ := req.Options[longOptionName].(bool)
for _, o := range out.Entries {
if long {
if o.Type == int(mfs.TDir) {
o.Name += "/"
}
fmt.Fprintf(buf, "%s\t%s\t%d\n", o.Name, o.Hash, o.Size)
fmt.Fprintf(w, "%s\t%s\t%d\n", o.Name, o.Hash, o.Size)
} else {
fmt.Fprintf(buf, "%s\n", o.Name)
fmt.Fprintf(w, "%s\n", o.Name)
}
}
return buf, nil
},
return nil
}),
},
Type: filesLsOutput{},
}
@ -546,7 +509,7 @@ const (
filesCountOptionName = "count"
)
var filesReadCmd = &oldcmds.Command{
var filesReadCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Read a file in a given mfs.",
ShortDescription: `
@ -567,81 +530,62 @@ Examples:
cmdkit.Int64Option(filesOffsetOptionName, "o", "Byte offset to begin reading from."),
cmdkit.Int64Option(filesCountOptionName, "n", "Maximum number of bytes to read."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
path, err := checkPath(req.Arguments()[0])
path, err := checkPath(req.Arguments[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
fsn, err := mfs.Lookup(n.FilesRoot, path)
fsn, err := mfs.Lookup(nd.FilesRoot, path)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
fi, ok := fsn.(*mfs.File)
if !ok {
res.SetError(fmt.Errorf("%s was not a file", path), cmdkit.ErrNormal)
return
return fmt.Errorf("%s was not a file", path)
}
rfd, err := fi.Open(mfs.OpenReadOnly, false)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
defer rfd.Close()
offset, _, err := req.Option(offsetOptionName).Int64()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
offset, _ := req.Options[offsetOptionName].(int64)
if offset < 0 {
res.SetError(fmt.Errorf("cannot specify negative offset"), cmdkit.ErrNormal)
return
return fmt.Errorf("cannot specify negative offset")
}
filen, err := rfd.Size()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if int64(offset) > filen {
res.SetError(fmt.Errorf("offset was past end of file (%d > %d)", offset, filen), cmdkit.ErrNormal)
return
return fmt.Errorf("offset was past end of file (%d > %d)", offset, filen)
}
_, err = rfd.Seek(int64(offset), io.SeekStart)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
var r io.Reader = &contextReaderWrapper{R: rfd, ctx: req.Context()}
count, found, err := req.Option(filesCountOptionName).Int64()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
var r io.Reader = &contextReaderWrapper{R: rfd, ctx: req.Context}
count, found := req.Options[filesCountOptionName].(int64)
if found {
if count < 0 {
res.SetError(fmt.Errorf("cannot specify negative 'count'"), cmdkit.ErrNormal)
return
return fmt.Errorf("cannot specify negative 'count'")
}
r = io.LimitReader(r, int64(count))
}
res.SetOutput(r)
return res.Emit(r)
},
}
@ -658,7 +602,7 @@ func (crw *contextReaderWrapper) Read(b []byte) (int, error) {
return crw.R.CtxReadFull(crw.ctx, b)
}
var filesMvCmd = &oldcmds.Command{
var filesMvCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Move files.",
ShortDescription: `
@ -675,31 +619,22 @@ Example:
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 oldcmds.Request, res oldcmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
src, err := checkPath(req.Arguments()[0])
src, err := checkPath(req.Arguments[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
dst, err := checkPath(req.Arguments()[1])
dst, err := checkPath(req.Arguments[1])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
err = mfs.Mv(n.FilesRoot, src, dst)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
res.SetOutput(nil)
return mfs.Mv(nd.FilesRoot, src, dst)
},
}
@ -849,7 +784,7 @@ stat' on the file or any of its ancestors.
},
}
var filesMkdirCmd = &oldcmds.Command{
var filesMkdirCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Make directories.",
ShortDescription: `
@ -875,26 +810,23 @@ Examples:
cidVersionOption,
hashOption,
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
dashp, _, _ := req.Option(filesParentsOptionName).Bool()
dirtomake, err := checkPath(req.Arguments()[0])
dashp, _ := req.Options[filesParentsOptionName].(bool)
dirtomake, err := checkPath(req.Arguments[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
flush, _, _ := req.Option(filesFlushOptionName).Bool()
flush, _ := req.Options[filesFlushOptionName].(bool)
prefix, err := getPrefix(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
root := n.FilesRoot
@ -903,16 +835,12 @@ Examples:
Flush: flush,
CidBuilder: prefix,
})
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
res.SetOutput(nil)
return err
},
}
var filesFlushCmd = &oldcmds.Command{
var filesFlushCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Flush a given path's data to disk.",
ShortDescription: `
@ -923,29 +851,22 @@ are run with the '--flush=false'.
Arguments: []cmdkit.Argument{
cmdkit.StringArg("path", false, false, "Path to flush. Default: '/'."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
nd, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
path := "/"
if len(req.Arguments()) > 0 {
path = req.Arguments()[0]
if len(req.Arguments) > 0 {
path = req.Arguments[0]
}
err = mfs.FlushPath(nd.FilesRoot, path)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
res.SetOutput(nil)
return mfs.FlushPath(nd.FilesRoot, path)
},
}
var filesChcidCmd = &oldcmds.Command{
var filesChcidCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Change the cid version or hash function of the root node of a given path.",
ShortDescription: `
@ -959,33 +880,25 @@ Change the cid version or hash function of the root node of a given path.
cidVersionOption,
hashOption,
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
nd, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
path := "/"
if len(req.Arguments()) > 0 {
path = req.Arguments()[0]
if len(req.Arguments) > 0 {
path = req.Arguments[0]
}
flush, _, _ := req.Option(filesFlushOptionName).Bool()
flush, _ := req.Options[filesFlushOptionName].(bool)
prefix, err := getPrefix(req)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
err = updatePath(nd.FilesRoot, path, prefix, flush)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
res.SetOutput(nil)
return updatePath(nd.FilesRoot, path, prefix, flush)
},
}
@ -1013,7 +926,7 @@ func updatePath(rt *mfs.Root, pth string, builder cid.Builder, flush bool) error
return nil
}
var filesRmCmd = &oldcmds.Command{
var filesRmCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Remove a file.",
ShortDescription: `
@ -1032,27 +945,22 @@ Remove files or directories.
cmdkit.StringArg("path", true, true, "File to remove."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Recursively remove directories."),
cmdkit.BoolOption("force", "Forcibly remove target at path; implies -r for directories"),
cmdkit.BoolOption(recursiveOptionName, "r", "Recursively remove directories."),
cmdkit.BoolOption(forceOptionName, "Forcibly remove target at path; implies -r for directories"),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
defer res.SetOutput(nil)
nd, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
path, err := checkPath(req.Arguments()[0])
path, err := checkPath(req.Arguments[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if path == "/" {
res.SetError(fmt.Errorf("cannot delete root"), cmdkit.ErrNormal)
return
return fmt.Errorf("cannot delete root")
}
// 'rm a/b/c/' will fail unless we trim the slash at the end
@ -1063,66 +971,48 @@ 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), cmdkit.ErrNormal)
return
return fmt.Errorf("parent lookup: %s", err)
}
pdir, ok := parent.(*mfs.Directory)
if !ok {
res.SetError(fmt.Errorf("no such file or directory: %s", path), cmdkit.ErrNormal)
return
return fmt.Errorf("no such file or directory: %s", path)
}
var success bool
defer func() {
if success {
err := pdir.Flush()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
}
}()
// if '--force' specified, it will remove anything else,
// including file, directory, corrupted node, etc
force, _, _ := req.Option("force").Bool()
force, _ := req.Options[forceOptionName].(bool)
if force {
err := pdir.Unlink(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
success = true
return
return pdir.Flush()
}
// get child node by name, when the node is corrupted and nonexistent,
// it will return specific error.
child, err := pdir.Child(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
dashr, _, _ := req.Option("r").Bool()
dashr, _ := req.Options[recursiveOptionName].(bool)
switch child.(type) {
case *mfs.Directory:
if !dashr {
res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmdkit.ErrNormal)
return
return fmt.Errorf("%s is a directory, use -r to remove directories", path)
}
}
err = pdir.Unlink(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
success = true
return pdir.Flush()
},
}
@ -1155,9 +1045,9 @@ func getPrefixNew(req *cmds.Request) (cid.Builder, error) {
return &prefix, nil
}
func getPrefix(req oldcmds.Request) (cid.Builder, error) {
cidVer, cidVerSet, _ := req.Option(filesCidVersionOptionName).Int()
hashFunStr, hashFunSet, _ := req.Option(filesHashOptionName).String()
func getPrefix(req *cmds.Request) (cid.Builder, error) {
cidVer, cidVerSet := req.Options[filesCidVersionOptionName].(int)
hashFunStr, hashFunSet := req.Options[filesHashOptionName].(string)
if !cidVerSet && !hashFunSet {
return nil, nil