diff --git a/core/commands/block.go b/core/commands/block.go index 2e65fef8c..b0b0acf13 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -1,23 +1,19 @@ package commands import ( - "bytes" - "context" - "errors" "fmt" "io" - "io/ioutil" "os" util "github.com/ipfs/go-ipfs/blocks/blockstoreutil" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" e "github.com/ipfs/go-ipfs/core/commands/e" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" + "github.com/ipfs/go-ipfs/core/coreapi/interface/options" "gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds" mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash" "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit" - blocks "gx/ipfs/QmWAzSEoqZ6xU6pu8yL8e5WaMb7wtbfbhhN4p1DknUPtr3/go-block-format" - cid "gx/ipfs/QmZFbDTY9jfSBms2MchvYM9oYRbAF19K7Pby47yDBfpPrb/go-cid" ) type BlockStat struct { @@ -64,15 +60,27 @@ on raw IPFS blocks. It outputs the following to stdout: cmdkit.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) { - b, err := getBlockForKey(req.Context, env, req.Arguments[0]) + api, err := cmdenv.GetApi(env) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + p, err := coreiface.ParsePath(req.Arguments[0]) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + b, err := api.Block().Stat(req.Context, p) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } err = cmds.EmitOnce(res, &BlockStat{ - Key: b.Cid().String(), - Size: len(b.RawData()), + Key: b.Path().Cid().String(), + Size: b.Size(), }) if err != nil { log.Error(err) @@ -104,13 +112,25 @@ It outputs to stdout, and is a base58 encoded multihash. cmdkit.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) { - b, err := getBlockForKey(req.Context, env, req.Arguments[0]) + api, err := cmdenv.GetApi(env) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - err = res.Emit(bytes.NewReader(b.RawData())) + p, err := coreiface.ParsePath(req.Arguments[0]) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + r, err := api.Block().Get(req.Context, p) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } + + err = res.Emit(r) if err != nil { log.Error(err) } @@ -138,7 +158,7 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1. cmdkit.IntOption("mhlen", "multihash hash length").WithDefault(-1), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) { - n, err := cmdenv.GetNode(env) + api, err := cmdenv.GetApi(env) if err != nil { res.SetError(err, cmdkit.ErrNormal) return @@ -150,18 +170,6 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1. return } - data, err := ioutil.ReadAll(file) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - err = file.Close() - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - mhtype, _ := req.Options["mhtype"].(string) mhtval, ok := mh.Names[mhtype] if !ok { @@ -170,8 +178,11 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1. return } - var pref cid.Prefix - pref.Version = 1 + mhlen, ok := req.Options["mhlen"].(int) + if !ok { + res.SetError("missing option \"mhlen\"", cmdkit.ErrNormal) + return + } format, formatSet := req.Options["format"].(string) if !formatSet { @@ -182,50 +193,15 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1. } } - if format == "v0" { - pref.Version = 0 - } - formatval, ok := cid.Codecs[format] - if !ok { - res.SetError(fmt.Errorf("unrecognized format: '%s'", format), cmdkit.ErrNormal) - return - } - if mhtval != mh.SHA2_256 && pref.Version == 0 { - res.SetError(errors.New("cannot generate CIDv0 with non-sha256 hash function"), cmdkit.ErrNormal) - return - } - - pref.Codec = formatval - pref.MhType = mhtval - - mhlen, ok := req.Options["mhlen"].(int) - if !ok { - res.SetError("missing option \"mhlen\"", cmdkit.ErrNormal) - return - } - pref.MhLength = mhlen - - bcid, err := pref.Sum(data) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - b, err := blocks.NewBlockWithCid(data, bcid) - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } - - err = n.Blocks.AddBlock(b) + p, err := api.Block().Put(req.Context, file, options.Block.Hash(mhtval, mhlen), options.Block.Format(format)) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } err = cmds.EmitOnce(res, &BlockStat{ - Key: b.Cid().String(), - Size: len(data), + Key: p.Path().Cid().String(), + Size: p.Size(), }) if err != nil { log.Error(err) @@ -244,29 +220,6 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1. Type: BlockStat{}, } -func getBlockForKey(ctx context.Context, env cmds.Environment, skey string) (blocks.Block, error) { - if len(skey) == 0 { - return nil, fmt.Errorf("zero length cid invalid") - } - - n, err := cmdenv.GetNode(env) - if err != nil { - return nil, err - } - - c, err := cid.Decode(skey) - if err != nil { - return nil, err - } - - b, err := n.Blocks.GetBlock(ctx, c) - if err != nil { - return nil, err - } - - return b, nil -} - var blockRmCmd = &cmds.Command{ Helptext: cmdkit.HelpText{ Tagline: "Remove IPFS block(s).", @@ -283,38 +236,40 @@ It takes a list of base58 encoded multihashes to remove. cmdkit.BoolOption("quiet", "q", "Write minimal output."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) { - n, err := cmdenv.GetNode(env) + api, err := cmdenv.GetApi(env) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - hashes := req.Arguments + force, _ := req.Options["force"].(bool) quiet, _ := req.Options["quiet"].(bool) - cids := make([]*cid.Cid, 0, len(hashes)) - for _, hash := range hashes { - c, err := cid.Decode(hash) + + // TODO: use batching coreapi when done + for _, b := range req.Arguments { + p, err := coreiface.ParsePath(b) if err != nil { - err = fmt.Errorf("invalid content id: %s (%s)", hash, err) res.SetError(err, cmdkit.ErrNormal) return } - cids = append(cids, c) - } - ch, err := util.RmBlocks(n.Blockstore, n.Pinning, cids, util.RmBlocksOpts{ - Quiet: quiet, - Force: force, - }) + rp, err := api.ResolvePath(req.Context, p) + if err != nil { + res.SetError(err, cmdkit.ErrNormal) + return + } - if err != nil { - res.SetError(err, cmdkit.ErrNormal) - return - } + err = api.Block().Rm(req.Context, rp, options.Block.Force(force)) + if err != nil && !quiet { + res.Emit(&util.RemovedBlock{ + Hash: rp.Cid().String(), + Error: err.Error(), + }) + } - err = res.Emit(ch) - if err != nil { - log.Error(err) + res.Emit(&util.RemovedBlock{ + Hash: rp.Cid().String(), + }) } }, PostRun: cmds.PostRunMap{ diff --git a/core/coreapi/block.go b/core/coreapi/block.go index 1a03b6dd8..4c9f732e7 100644 --- a/core/coreapi/block.go +++ b/core/coreapi/block.go @@ -24,7 +24,7 @@ type BlockStat struct { size int } -func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.ResolvedPath, error) { +func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.BlockStat, error) { settings, err := caopts.BlockPutOptions(opts...) if err != nil { return nil, err @@ -65,7 +65,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc return nil, err } - return coreiface.IpldPath(b.Cid()), nil + return &BlockStat{path: coreiface.IpldPath(b.Cid()), size: len(data)}, nil } func (api *BlockAPI) Get(ctx context.Context, p coreiface.Path) (io.Reader, error) { diff --git a/core/coreapi/block_test.go b/core/coreapi/block_test.go index d50c34f98..7026a1681 100644 --- a/core/coreapi/block_test.go +++ b/core/coreapi/block_test.go @@ -23,8 +23,8 @@ func TestBlockPut(t *testing.T) { t.Error(err) } - if res.Cid().String() != "QmPyo15ynbVrSTVdJL9th7JysHaAbXt9dM9tXk1bMHbRtk" { - t.Errorf("got wrong cid: %s", res.Cid().String()) + if res.Path().Cid().String() != "QmPyo15ynbVrSTVdJL9th7JysHaAbXt9dM9tXk1bMHbRtk" { + t.Errorf("got wrong cid: %s", res.Path().Cid().String()) } } @@ -40,8 +40,8 @@ func TestBlockPutFormat(t *testing.T) { t.Error(err) } - if res.Cid().String() != "zdpuAn4amuLWo8Widi5v6VQpuo2dnpnwbVE3oB6qqs7mDSeoa" { - t.Errorf("got wrong cid: %s", res.Cid().String()) + if res.Path().Cid().String() != "zdpuAn4amuLWo8Widi5v6VQpuo2dnpnwbVE3oB6qqs7mDSeoa" { + t.Errorf("got wrong cid: %s", res.Path().Cid().String()) } } @@ -57,8 +57,8 @@ func TestBlockPutHash(t *testing.T) { t.Error(err) } - if res.Cid().String() != "zBurKB9YZkcDf6xa53WBE8CFX4ydVqAyf9KPXBFZt5stJzEstaS8Hukkhu4gwpMtc1xHNDbzP7sPtQKyWsP3C8fbhkmrZ" { - t.Errorf("got wrong cid: %s", res.Cid().String()) + if res.Path().Cid().String() != "zBurKB9YZkcDf6xa53WBE8CFX4ydVqAyf9KPXBFZt5stJzEstaS8Hukkhu4gwpMtc1xHNDbzP7sPtQKyWsP3C8fbhkmrZ" { + t.Errorf("got wrong cid: %s", res.Path().Cid().String()) } } @@ -74,7 +74,7 @@ func TestBlockGet(t *testing.T) { t.Error(err) } - r, err := api.Block().Get(ctx, res) + r, err := api.Block().Get(ctx, res.Path()) if err != nil { t.Error(err) } @@ -101,7 +101,7 @@ func TestBlockRm(t *testing.T) { t.Error(err) } - r, err := api.Block().Get(ctx, res) + r, err := api.Block().Get(ctx, res.Path()) if err != nil { t.Error(err) } @@ -115,12 +115,12 @@ func TestBlockRm(t *testing.T) { t.Error("didn't get correct data back") } - err = api.Block().Rm(ctx, res) + err = api.Block().Rm(ctx, res.Path()) if err != nil { t.Error(err) } - _, err = api.Block().Get(ctx, res) + _, err = api.Block().Get(ctx, res.Path()) if err == nil { t.Error("expected err to exist") } @@ -128,7 +128,7 @@ func TestBlockRm(t *testing.T) { t.Errorf("unexpected error; %s", err.Error()) } - err = api.Block().Rm(ctx, res) + err = api.Block().Rm(ctx, res.Path()) if err == nil { t.Error("expected err to exist") } @@ -136,7 +136,7 @@ func TestBlockRm(t *testing.T) { t.Errorf("unexpected error; %s", err.Error()) } - err = api.Block().Rm(ctx, res, opt.Block.Force(true)) + err = api.Block().Rm(ctx, res.Path(), opt.Block.Force(true)) if err != nil { t.Error(err) } @@ -154,12 +154,12 @@ func TestBlockStat(t *testing.T) { t.Error(err) } - stat, err := api.Block().Stat(ctx, res) + stat, err := api.Block().Stat(ctx, res.Path()) if err != nil { t.Error(err) } - if stat.Path().String() != res.String() { + if stat.Path().String() != res.Path().String() { t.Error("paths don't match") } diff --git a/core/coreapi/interface/block.go b/core/coreapi/interface/block.go index 468c00947..b99b05fdb 100644 --- a/core/coreapi/interface/block.go +++ b/core/coreapi/interface/block.go @@ -19,7 +19,7 @@ type BlockStat interface { // BlockAPI specifies the interface to the block layer type BlockAPI interface { // Put imports raw block data, hashing it using specified settings. - Put(context.Context, io.Reader, ...options.BlockPutOption) (ResolvedPath, error) + Put(context.Context, io.Reader, ...options.BlockPutOption) (BlockStat, error) // Get attempts to resolve the path and return a reader for data in the block Get(context.Context, Path) (io.Reader, error) diff --git a/core/coreapi/path_test.go b/core/coreapi/path_test.go index 76e78b545..e71d94df9 100644 --- a/core/coreapi/path_test.go +++ b/core/coreapi/path_test.go @@ -31,7 +31,7 @@ func TestMutablePath(t *testing.T) { t.Error(err) } - if blk.Mutable() { + if blk.Path().Mutable() { t.Error("expected /ipld path to be immutable") } } @@ -129,7 +129,7 @@ func TestPathRoot(t *testing.T) { t.Error(err) } - obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"/": "`+blk.Cid().String()+`"}}`)) + obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"/": "`+blk.Path().Cid().String()+`"}}`)) if err != nil { t.Fatal(err) } @@ -148,7 +148,7 @@ func TestPathRoot(t *testing.T) { t.Error("unexpected path root") } - if rp.Cid().String() != blk.Cid().String() { + if rp.Cid().String() != blk.Path().Cid().String() { t.Error("unexpected path cid") } }