From 32ceaa61e81a7e0e9d53ea3a9a78e4f101fb58ea Mon Sep 17 00:00:00 2001 From: Stephen Whitmore Date: Sat, 16 Jan 2016 03:11:36 +0100 Subject: [PATCH] Resolves paths in 'pin rm' without network lookup. Fixes ipfs/go-ipfs#2155 by turning the hash path arguments into keys and unpinning directly, rather than running a full core.Resolve on them. This lets users fail fast when they try to remove pins that they don't have locally. Note that this will only work when the path is of the form or /ipfs/. Given e.g. /ipfs//foo, foo's key cannot be known without first resolving , which may involve talking to the network. License: MIT Signed-off-by: Stephen Whitmore --- core/corerepo/pinning.go | 17 ++++++++--------- core/pathresolver.go | 29 +++++++++++++++++++++++++++++ test/sharness/t0081-repo-pinning.sh | 7 +++++++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/core/corerepo/pinning.go b/core/corerepo/pinning.go index 0c30b5592..4cb1ec7f2 100644 --- a/core/corerepo/pinning.go +++ b/core/corerepo/pinning.go @@ -60,22 +60,21 @@ func Pin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) func Unpin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) ([]key.Key, error) { - dagnodes := make([]*merkledag.Node, 0) - for _, fpath := range paths { - dagnode, err := core.Resolve(ctx, n, path.Path(fpath)) + var unpinned []key.Key + for _, p := range paths { + p, err := path.ParsePath(p) if err != nil { return nil, err } - dagnodes = append(dagnodes, dagnode) - } - var unpinned []key.Key - for _, dagnode := range dagnodes { - k, _ := dagnode.Key() + k, err := core.ResolveToKey(ctx, n, p) + if err != nil { + return nil, err + } ctx, cancel := context.WithCancel(ctx) defer cancel() - err := n.Pinning.Unpin(ctx, k, recursive) + err = n.Pinning.Unpin(ctx, k, recursive) if err != nil { return nil, err } diff --git a/core/pathresolver.go b/core/pathresolver.go index 153f560bc..515899969 100644 --- a/core/pathresolver.go +++ b/core/pathresolver.go @@ -6,6 +6,7 @@ import ( context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + key "github.com/ipfs/go-ipfs/blocks/key" merkledag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" ) @@ -55,3 +56,31 @@ func Resolve(ctx context.Context, n *IpfsNode, p path.Path) (*merkledag.Node, er // ok, we have an ipfs path now (or what we'll treat as one) return n.Resolver.ResolvePath(ctx, p) } + +// ResolveToKey resolves a path to a key. +// +// It first checks if the path is already in the form of just a key ( or +// /ipfs/) and returns immediately if so. Otherwise, it falls back onto +// Resolve to perform resolution of the dagnode being referenced. +func ResolveToKey(ctx context.Context, n *IpfsNode, p path.Path) (key.Key, error) { + + // If the path is simply a key, parse and return it. Parsed paths are already + // normalized (read: prepended with /ipfs/ if needed), so segment[1] should + // always be the key. + if p.IsJustAKey() { + return key.B58KeyDecode(p.Segments()[1]), nil + } + + // Fall back onto regular dagnode resolution. + dagnode, err := Resolve(ctx, n, p) + if err != nil { + return key.Key(""), err + } + + // Extract and return the node's key. + k, err := dagnode.Key() + if err != nil { + return key.Key(""), err + } + return k, nil +} diff --git a/test/sharness/t0081-repo-pinning.sh b/test/sharness/t0081-repo-pinning.sh index f57a86303..be0e2e7ea 100755 --- a/test/sharness/t0081-repo-pinning.sh +++ b/test/sharness/t0081-repo-pinning.sh @@ -279,6 +279,13 @@ test_expect_success "test add nopin dir" ' ' +FICTIONAL_HASH="QmXV4f9v8a56MxWKBhP3ETsz4EaafudU1cKfPaaJnenc48" +test_launch_ipfs_daemon +test_expect_success "test unpinning a hash that's not pinned" " + test_expect_code 1 ipfs pin rm $FICTIONAL_HASH --timeout=5s +" +test_kill_ipfs_daemon + # test_kill_ipfs_daemon test_done