diff --git a/core/commands/resolve.go b/core/commands/resolve.go index e8c25a4c1..f6ad91eae 100644 --- a/core/commands/resolve.go +++ b/core/commands/resolve.go @@ -5,7 +5,7 @@ import ( "strings" cmds "github.com/ipfs/go-ipfs/commands" - namesys "github.com/ipfs/go-ipfs/namesys" + "github.com/ipfs/go-ipfs/core" path "github.com/ipfs/go-ipfs/path" u "github.com/ipfs/go-ipfs/util" ) @@ -46,6 +46,11 @@ Resolve the value of another name recursively: > ipfs resolve -r /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj +Resolve the value of an IPFS DAG path: + + > ipfs resolve /ipfs/QmeZy1fGbwgVSrqbfh9fKQrAWgeyRnj7h8fsHS1oy3k99x/beep/boop + /ipfs/QmYRMjyvAiHKN9UTi8Bzt1HUspmSRD8T8DwxfSMzLgBon1 + `, }, @@ -73,18 +78,38 @@ Resolve the value of another name recursively: name := req.Arguments()[0] recursive, _, _ := req.Option("recursive").Bool() - depth := 1 - if recursive { - depth = namesys.DefaultDepthLimit + + // the case when ipns is resolved step by step + if strings.HasPrefix(name, "/ipns/") && !recursive { + p, err := n.Namesys.ResolveN(req.Context(), name, 1) + if err != nil { + res.SetError(err, cmds.ErrNormal) + return + } + res.SetOutput(&ResolvedPath{p}) + return } - output, err := n.Namesys.ResolveN(req.Context(), name, depth) + // else, ipfs path or ipns with recursive flag + p, err := path.ParsePath(name) if err != nil { res.SetError(err, cmds.ErrNormal) return } - res.SetOutput(&ResolvedPath{output}) + node, err := core.Resolve(req.Context(), n, p) + if err != nil { + res.SetError(err, cmds.ErrNormal) + return + } + + key, err := node.Key() + if err != nil { + res.SetError(err, cmds.ErrNormal) + return + } + + res.SetOutput(&ResolvedPath{path.FromKey(key)}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { diff --git a/core/pathresolver.go b/core/pathresolver.go index 610eeb50b..153f560bc 100644 --- a/core/pathresolver.go +++ b/core/pathresolver.go @@ -17,7 +17,7 @@ var ErrNoNamesys = errors.New( // Resolve resolves the given path by parsing out protocol-specific // entries (e.g. /ipns/) and then going through the /ipfs/ -// entries and returning the final merkledage node. Effectively +// entries and returning the final merkledag node. Effectively // enables /ipns/, /dns/, etc. in commands. func Resolve(ctx context.Context, n *IpfsNode, p path.Path) (*merkledag.Node, error) { if strings.HasPrefix(p.String(), "/ipns/") { diff --git a/test/sharness/t0160-resolve.sh b/test/sharness/t0160-resolve.sh new file mode 100755 index 000000000..02b457c54 --- /dev/null +++ b/test/sharness/t0160-resolve.sh @@ -0,0 +1,117 @@ +#!/bin/sh + +test_description="Test resolve command" + +. lib/test-lib.sh + +test_init_ipfs + +test_expect_success "resolve: prepare files" ' + mkdir -p a/b && + echo "a/b/c" >a/b/c && + a_hash=$(ipfs add -q -r a | tail -n1) && + b_hash=$(ipfs add -q -r a/b | tail -n1) && + c_hash=$(ipfs add -q -r a/b/c | tail -n1) +' + +test_resolve_setup_name() { + ref=$1 + + test_expect_success "resolve: prepare name" ' + id_hash=$(ipfs id -f="") && + ipfs name publish "$ref" && + printf "$ref" >expected_nameval && + ipfs name resolve >actual_nameval && + test_cmp expected_nameval actual_nameval + ' +} + +test_resolve_setup_name_fail() { + ref=$1 + + test_expect_failure "resolve: prepare name" ' + id_hash=$(ipfs id -f="") && + ipfs name publish "$ref" && + printf "$ref" >expected_nameval && + ipfs name resolve >actual_nameval && + test_cmp expected_nameval actual_nameval + ' +} + +test_resolve() { + src=$1 + dst=$2 + + test_expect_success "resolve succeeds: $src" ' + ipfs resolve -r "$src" >actual + ' + + test_expect_success "resolved correctly: $src -> $dst" ' + printf "$dst" >expected && + test_cmp expected actual + ' +} + +test_resolve_cmd() { + + test_resolve "/ipfs/$a_hash" "/ipfs/$a_hash" + test_resolve "/ipfs/$a_hash/b" "/ipfs/$b_hash" + test_resolve "/ipfs/$a_hash/b/c" "/ipfs/$c_hash" + test_resolve "/ipfs/$b_hash/c" "/ipfs/$c_hash" + + test_resolve_setup_name "/ipfs/$a_hash" + test_resolve "/ipns/$id_hash" "/ipfs/$a_hash" + test_resolve "/ipns/$id_hash/b" "/ipfs/$b_hash" + test_resolve "/ipns/$id_hash/b/c" "/ipfs/$c_hash" + + test_resolve_setup_name "/ipfs/$b_hash" + test_resolve "/ipns/$id_hash" "/ipfs/$b_hash" + test_resolve "/ipns/$id_hash/c" "/ipfs/$c_hash" + + test_resolve_setup_name "/ipfs/$c_hash" + test_resolve "/ipns/$id_hash" "/ipfs/$c_hash" +} + +#todo remove this once the online resolve is fixed +test_resolve_fail() { + src=$1 + dst=$2 + + test_expect_failure "resolve succeeds: $src" ' + ipfs resolve "$src" >actual + ' + + test_expect_failure "resolved correctly: $src -> $dst" ' + printf "$dst" >expected && + test_cmp expected actual + ' +} + +test_resolve_cmd_fail() { + test_resolve "/ipfs/$a_hash" "/ipfs/$a_hash" + test_resolve "/ipfs/$a_hash/b" "/ipfs/$b_hash" + test_resolve "/ipfs/$a_hash/b/c" "/ipfs/$c_hash" + test_resolve "/ipfs/$b_hash/c" "/ipfs/$c_hash" + + test_resolve_setup_name_fail "/ipfs/$a_hash" + test_resolve_fail "/ipns/$id_hash" "/ipfs/$a_hash" + test_resolve_fail "/ipns/$id_hash/b" "/ipfs/$b_hash" + test_resolve_fail "/ipns/$id_hash/b/c" "/ipfs/$c_hash" + + test_resolve_setup_name_fail "/ipfs/$b_hash" + test_resolve_fail "/ipns/$id_hash" "/ipfs/$b_hash" + test_resolve_fail "/ipns/$id_hash/c" "/ipfs/$c_hash" + + test_resolve_setup_name_fail "/ipfs/$c_hash" + test_resolve_fail "/ipns/$id_hash" "/ipfs/$c_hash" +} + +# should work offline +test_resolve_cmd + +# should work online +test_launch_ipfs_daemon +test_resolve_cmd_fail +test_kill_ipfs_daemon + +test_done