mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-20 19:19:06 +08:00
Merge pull request #5484 from ipfs/fix/resolve-hamt
resolve: use unixfs ResolveOnce
This commit is contained in:
@ -2,18 +2,21 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cmds "github.com/ipfs/go-ipfs/commands"
|
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
|
||||||
"github.com/ipfs/go-ipfs/core"
|
|
||||||
e "github.com/ipfs/go-ipfs/core/commands/e"
|
e "github.com/ipfs/go-ipfs/core/commands/e"
|
||||||
ncmd "github.com/ipfs/go-ipfs/core/commands/name"
|
ncmd "github.com/ipfs/go-ipfs/core/commands/name"
|
||||||
|
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
|
||||||
|
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
|
||||||
ns "github.com/ipfs/go-ipfs/namesys"
|
ns "github.com/ipfs/go-ipfs/namesys"
|
||||||
nsopts "github.com/ipfs/go-ipfs/namesys/opts"
|
nsopts "github.com/ipfs/go-ipfs/namesys/opts"
|
||||||
path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
|
path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
|
||||||
|
|
||||||
|
"gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds"
|
||||||
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
|
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,12 +65,17 @@ Resolve the value of an IPFS DAG path:
|
|||||||
},
|
},
|
||||||
Options: []cmdkit.Option{
|
Options: []cmdkit.Option{
|
||||||
cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."),
|
cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."),
|
||||||
cmdkit.UintOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
|
cmdkit.IntOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
|
||||||
cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
|
cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
|
||||||
},
|
},
|
||||||
Run: func(req cmds.Request, res cmds.Response) {
|
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
|
||||||
|
api, err := cmdenv.GetApi(env)
|
||||||
|
if err != nil {
|
||||||
|
res.SetError(err, cmdkit.ErrNormal)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
n, err := req.InvocContext().GetNode()
|
n, err := cmdenv.GetNode(env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.SetError(err, cmdkit.ErrNormal)
|
res.SetError(err, cmdkit.ErrNormal)
|
||||||
return
|
return
|
||||||
@ -81,16 +89,19 @@ Resolve the value of an IPFS DAG path:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
name := req.Arguments()[0]
|
name := req.Arguments[0]
|
||||||
recursive, _, _ := req.Option("recursive").Bool()
|
recursive, _ := req.Options["recursive"].(bool)
|
||||||
|
|
||||||
// the case when ipns is resolved step by step
|
// the case when ipns is resolved step by step
|
||||||
if strings.HasPrefix(name, "/ipns/") && !recursive {
|
if strings.HasPrefix(name, "/ipns/") && !recursive {
|
||||||
rc, rcok, _ := req.Option("dht-record-count").Int()
|
rc, rcok := req.Options["dht-record-count"].(uint)
|
||||||
dhtt, dhttok, _ := req.Option("dht-timeout").String()
|
dhtt, dhttok := req.Options["dht-timeout"].(string)
|
||||||
ropts := []nsopts.ResolveOpt{nsopts.Depth(1)}
|
ropts := []options.NameResolveOption{
|
||||||
|
options.Name.ResolveOption(nsopts.Depth(1)),
|
||||||
|
}
|
||||||
|
|
||||||
if rcok {
|
if rcok {
|
||||||
ropts = append(ropts, nsopts.DhtRecordCount(uint(rc)))
|
ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
|
||||||
}
|
}
|
||||||
if dhttok {
|
if dhttok {
|
||||||
d, err := time.ParseDuration(dhtt)
|
d, err := time.ParseDuration(dhtt)
|
||||||
@ -102,48 +113,45 @@ Resolve the value of an IPFS DAG path:
|
|||||||
res.SetError(errors.New("DHT timeout value must be >= 0"), cmdkit.ErrNormal)
|
res.SetError(errors.New("DHT timeout value must be >= 0"), cmdkit.ErrNormal)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ropts = append(ropts, nsopts.DhtTimeout(d))
|
ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
|
||||||
}
|
}
|
||||||
p, err := n.Namesys.Resolve(req.Context(), name, ropts...)
|
p, err := api.Name().Resolve(req.Context, name, ropts...)
|
||||||
// ErrResolveRecursion is fine
|
// ErrResolveRecursion is fine
|
||||||
if err != nil && err != ns.ErrResolveRecursion {
|
if err != nil && err != ns.ErrResolveRecursion {
|
||||||
res.SetError(err, cmdkit.ErrNormal)
|
res.SetError(err, cmdkit.ErrNormal)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res.SetOutput(&ncmd.ResolvedPath{Path: p})
|
cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path(p.String())})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// else, ipfs path or ipns with recursive flag
|
// else, ipfs path or ipns with recursive flag
|
||||||
p, err := path.ParsePath(name)
|
p, err := coreiface.ParsePath(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.SetError(err, cmdkit.ErrNormal)
|
res.SetError(err, cmdkit.ErrNormal)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, p)
|
rp, err := api.ResolvePath(req.Context, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.SetError(err, cmdkit.ErrNormal)
|
res.SetError(err, cmdkit.ErrNormal)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c := node.Cid()
|
c := rp.Cid()
|
||||||
|
|
||||||
res.SetOutput(&ncmd.ResolvedPath{Path: path.FromCid(c)})
|
cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.FromCid(c)})
|
||||||
},
|
},
|
||||||
Marshalers: cmds.MarshalerMap{
|
Encoders: cmds.EncoderMap{
|
||||||
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
|
||||||
v, err := unwrapOutput(res.Output())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
output, ok := v.(*ncmd.ResolvedPath)
|
output, ok := v.(*ncmd.ResolvedPath)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, e.TypeErr(output, v)
|
return e.TypeErr(output, v)
|
||||||
}
|
}
|
||||||
return strings.NewReader(output.Path.String() + "\n"), nil
|
|
||||||
},
|
fmt.Fprintln(w, output.Path.String())
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
Type: ncmd.ResolvedPath{},
|
Type: ncmd.ResolvedPath{},
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ var rootSubcommands = map[string]*cmds.Command{
|
|||||||
"ping": lgc.NewCommand(PingCmd),
|
"ping": lgc.NewCommand(PingCmd),
|
||||||
"p2p": lgc.NewCommand(P2PCmd),
|
"p2p": lgc.NewCommand(P2PCmd),
|
||||||
"refs": lgc.NewCommand(RefsCmd),
|
"refs": lgc.NewCommand(RefsCmd),
|
||||||
"resolve": lgc.NewCommand(ResolveCmd),
|
"resolve": ResolveCmd,
|
||||||
"swarm": lgc.NewCommand(SwarmCmd),
|
"swarm": lgc.NewCommand(SwarmCmd),
|
||||||
"tar": lgc.NewCommand(TarCmd),
|
"tar": lgc.NewCommand(TarCmd),
|
||||||
"file": lgc.NewCommand(unixfs.UnixFSCmd),
|
"file": lgc.NewCommand(unixfs.UnixFSCmd),
|
||||||
@ -183,7 +183,7 @@ var rootROSubcommands = map[string]*cmds.Command{
|
|||||||
"resolve": dag.DagResolveCmd,
|
"resolve": dag.DagResolveCmd,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
"resolve": lgc.NewCommand(ResolveCmd),
|
"resolve": ResolveCmd,
|
||||||
"version": lgc.NewCommand(VersionCmd),
|
"version": lgc.NewCommand(VersionCmd),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package options
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ropts "github.com/ipfs/go-ipfs/namesys/opts"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -14,9 +16,10 @@ type NamePublishSettings struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NameResolveSettings struct {
|
type NameResolveSettings struct {
|
||||||
Recursive bool
|
Local bool
|
||||||
Local bool
|
Cache bool
|
||||||
Cache bool
|
|
||||||
|
ResolveOpts []ropts.ResolveOpt
|
||||||
}
|
}
|
||||||
|
|
||||||
type NamePublishOption func(*NamePublishSettings) error
|
type NamePublishOption func(*NamePublishSettings) error
|
||||||
@ -40,9 +43,8 @@ func NamePublishOptions(opts ...NamePublishOption) (*NamePublishSettings, error)
|
|||||||
|
|
||||||
func NameResolveOptions(opts ...NameResolveOption) (*NameResolveSettings, error) {
|
func NameResolveOptions(opts ...NameResolveOption) (*NameResolveSettings, error) {
|
||||||
options := &NameResolveSettings{
|
options := &NameResolveSettings{
|
||||||
Recursive: false,
|
Local: false,
|
||||||
Local: false,
|
Cache: true,
|
||||||
Cache: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@ -80,15 +82,6 @@ func (nameOpts) Key(key string) NamePublishOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursive is an option for Name.Resolve which specifies whether to perform a
|
|
||||||
// recursive lookup. Default value is false
|
|
||||||
func (nameOpts) Recursive(recursive bool) NameResolveOption {
|
|
||||||
return func(settings *NameResolveSettings) error {
|
|
||||||
settings.Recursive = recursive
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local is an option for Name.Resolve which specifies if the lookup should be
|
// Local is an option for Name.Resolve which specifies if the lookup should be
|
||||||
// offline. Default value is false
|
// offline. Default value is false
|
||||||
func (nameOpts) Local(local bool) NameResolveOption {
|
func (nameOpts) Local(local bool) NameResolveOption {
|
||||||
@ -106,3 +99,11 @@ func (nameOpts) Cache(cache bool) NameResolveOption {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func (nameOpts) ResolveOption(opt ropts.ResolveOpt) NameResolveOption {
|
||||||
|
return func(settings *NameResolveSettings) error {
|
||||||
|
settings.ResolveOpts = append(settings.ResolveOpts, opt)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,17 +7,16 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
core "github.com/ipfs/go-ipfs/core"
|
"github.com/ipfs/go-ipfs/core"
|
||||||
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
|
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
|
||||||
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
|
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
|
||||||
keystore "github.com/ipfs/go-ipfs/keystore"
|
"github.com/ipfs/go-ipfs/keystore"
|
||||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
"github.com/ipfs/go-ipfs/namesys"
|
||||||
nsopts "github.com/ipfs/go-ipfs/namesys/opts"
|
|
||||||
ipath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
|
ipath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
|
||||||
|
|
||||||
crypto "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
|
"gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
|
||||||
peer "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer"
|
"gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer"
|
||||||
offline "gx/ipfs/QmSNe4MWVxZWk6UxxW2z2EKofFo4GdFzud1vfn1iVby3mj/go-ipfs-routing/offline"
|
"gx/ipfs/QmSNe4MWVxZWk6UxxW2z2EKofFo4GdFzud1vfn1iVby3mj/go-ipfs-routing/offline"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NameAPI CoreAPI
|
type NameAPI CoreAPI
|
||||||
@ -119,12 +118,7 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam
|
|||||||
name = "/ipns/" + name
|
name = "/ipns/" + name
|
||||||
}
|
}
|
||||||
|
|
||||||
var ropts []nsopts.ResolveOpt
|
output, err := resolver.Resolve(ctx, name, options.ResolveOpts...)
|
||||||
if !options.Recursive {
|
|
||||||
ropts = append(ropts, nsopts.Depth(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err := resolver.Resolve(ctx, name, ropts...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,44 @@
|
|||||||
package coreapi
|
package coreapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
"context"
|
||||||
fmt "fmt"
|
"fmt"
|
||||||
gopath "path"
|
gopath "path"
|
||||||
|
|
||||||
core "github.com/ipfs/go-ipfs/core"
|
"github.com/ipfs/go-ipfs/core"
|
||||||
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
|
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
|
||||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
|
||||||
uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io"
|
uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io"
|
||||||
ipfspath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
|
ipfspath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
|
||||||
resolver "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver"
|
"gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver"
|
||||||
|
|
||||||
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
|
"gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
|
||||||
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
|
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the
|
// ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the
|
||||||
// resolved Node.
|
// resolved Node.
|
||||||
func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (ipld.Node, error) {
|
func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (ipld.Node, error) {
|
||||||
return resolveNode(ctx, api.node.DAG, api.node.Namesys, p)
|
rp, err := api.ResolvePath(ctx, p)
|
||||||
}
|
|
||||||
|
|
||||||
// ResolvePath resolves the path `p` using Unixfs resolver, returns the
|
|
||||||
// resolved path.
|
|
||||||
func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.ResolvedPath, error) {
|
|
||||||
return resolvePath(ctx, api.node.DAG, api.node.Namesys, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveNode(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSystem, p coreiface.Path) (ipld.Node, error) {
|
|
||||||
rp, err := resolvePath(ctx, ng, nsys, p)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := ng.Get(ctx, rp.Cid())
|
node, err := api.node.DAG.Get(ctx, rp.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSystem, p coreiface.Path) (coreiface.ResolvedPath, error) {
|
// ResolvePath resolves the path `p` using Unixfs resolver, returns the
|
||||||
|
// resolved path.
|
||||||
|
func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.ResolvedPath, error) {
|
||||||
if _, ok := p.(coreiface.ResolvedPath); ok {
|
if _, ok := p.(coreiface.ResolvedPath); ok {
|
||||||
return p.(coreiface.ResolvedPath), nil
|
return p.(coreiface.ResolvedPath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ipath := ipfspath.Path(p.String())
|
ipath := ipfspath.Path(p.String())
|
||||||
ipath, err := core.ResolveIPNS(ctx, nsys, ipath)
|
ipath, err := core.ResolveIPNS(ctx, api.node.Namesys, ipath)
|
||||||
if err == core.ErrNoNamesys {
|
if err == core.ErrNoNamesys {
|
||||||
return nil, coreiface.ErrOffline
|
return nil, coreiface.ErrOffline
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -66,7 +57,7 @@ func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSyste
|
|||||||
}
|
}
|
||||||
|
|
||||||
r := &resolver.Resolver{
|
r := &resolver.Resolver{
|
||||||
DAG: ng,
|
DAG: api.node.DAG,
|
||||||
ResolveOnce: resolveOnce,
|
ResolveOnce: resolveOnce,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, r io.Reader) (coreiface.ResolvedP
|
|||||||
func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) {
|
func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) {
|
||||||
dget := api.node.DAG // TODO: use a session here once routing perf issues are resolved
|
dget := api.node.DAG // TODO: use a session here once routing perf issues are resolved
|
||||||
|
|
||||||
dagnode, err := resolveNode(ctx, dget, api.node.Namesys, p)
|
dagnode, err := api.core().ResolveNode(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,12 @@ test_expect_success "gateway can resolve sharded dirs" '
|
|||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success "'ipfs resolve' can resolve sharded dirs" '
|
||||||
|
echo /ipfs/QmZ3RfWk1u5LEGYLHA633B5TNJy3Du27K6Fny9wcxpowGS > expected &&
|
||||||
|
ipfs resolve "/ipfs/$SHARDED/file100" > actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
test_kill_ipfs_daemon
|
test_kill_ipfs_daemon
|
||||||
|
|
||||||
test_add_large_dir_v1() {
|
test_add_large_dir_v1() {
|
||||||
|
Reference in New Issue
Block a user