From 93d1a695d49867fcd530cd236ed6dd43ab454c50 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Fri, 16 Feb 2018 00:09:50 +0100 Subject: [PATCH] Feat: Separate "path" from "path/resolver" Currently the "path" module does two very different things: * Defines how ipfs paths look like and provides tools to parse/split etc. * Provides a resolver to resolve paths. This moves the resolver stuff to `path/resolver` and leaves the path utilities in `path`. The result is that now the IPFS `path` package just defines what a path looks like and becomes a module that can be exported/re-used without problems. Currently there are circular dependency cycles (resolve_test -> merkledag/utils, merkledag->path), which the prevent the export of merkledag itself. License: MIT Signed-off-by: Hector Sanjuan --- core/builder.go | 4 +-- core/commands/files.go | 3 +- core/commands/ls.go | 3 +- core/commands/pin.go | 5 ++-- core/commands/unixfs/ls.go | 6 ++-- core/core.go | 4 +-- core/coreapi/coreapi.go | 3 +- core/corehttp/gateway_handler.go | 5 ++-- core/corerepo/pinning.go | 5 ++-- core/coreunix/cat.go | 3 +- core/pathresolver.go | 5 ++-- path/path.go | 33 +++++++++++++++++++-- path/{ => resolver}/resolver.go | 43 ++++++---------------------- path/{ => resolver}/resolver_test.go | 5 ++-- 14 files changed, 71 insertions(+), 56 deletions(-) rename path/{ => resolver}/resolver.go (83%) rename path/{ => resolver}/resolver_test.go (92%) diff --git a/core/builder.go b/core/builder.go index 6ee365cc2..32006b24e 100644 --- a/core/builder.go +++ b/core/builder.go @@ -13,7 +13,7 @@ import ( offline "github.com/ipfs/go-ipfs/exchange/offline" filestore "github.com/ipfs/go-ipfs/filestore" dag "github.com/ipfs/go-ipfs/merkledag" - path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" pin "github.com/ipfs/go-ipfs/pin" repo "github.com/ipfs/go-ipfs/repo" cfg "github.com/ipfs/go-ipfs/repo/config" @@ -230,7 +230,7 @@ func setupNode(ctx context.Context, n *IpfsNode, cfg *BuildCfg) error { // this is kinda sketchy and could cause data loss n.Pinning = pin.NewPinner(n.Repo.Datastore(), n.DAG, internalDag) } - n.Resolver = path.NewBasicResolver(n.DAG) + n.Resolver = resolver.NewBasicResolver(n.DAG) if cfg.Online { if err := n.startLateOnlineServices(ctx); err != nil { diff --git a/core/commands/files.go b/core/commands/files.go index c8b9b9246..641b6bc91 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -19,6 +19,7 @@ import ( dag "github.com/ipfs/go-ipfs/merkledag" mfs "github.com/ipfs/go-ipfs/mfs" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" ft "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" @@ -352,7 +353,7 @@ func getNodeFromPath(ctx context.Context, node *core.IpfsNode, p string) (ipld.N return nil, err } - resolver := &path.Resolver{ + resolver := &resolver.Resolver{ DAG: node.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/commands/ls.go b/core/commands/ls.go index 6e5f0bdb8..6bfa91a67 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -13,6 +13,7 @@ import ( offline "github.com/ipfs/go-ipfs/exchange/offline" merkledag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" unixfs "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" unixfspb "github.com/ipfs/go-ipfs/unixfs/pb" @@ -92,7 +93,7 @@ The JSON output contains type information. return } - r := &path.Resolver{ + r := &resolver.Resolver{ DAG: nd.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/commands/pin.go b/core/commands/pin.go index 078013462..ddb470064 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -15,6 +15,7 @@ import ( offline "github.com/ipfs/go-ipfs/exchange/offline" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" pin "github.com/ipfs/go-ipfs/pin" uio "github.com/ipfs/go-ipfs/unixfs/io" @@ -387,7 +388,7 @@ new pin and removing the old one. return } - r := &path.Resolver{ + r := &resolver.Resolver{ DAG: n.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } @@ -501,7 +502,7 @@ func pinLsKeys(args []string, typeStr string, ctx context.Context, n *core.IpfsN keys := make(map[string]RefKeyObject) - r := &path.Resolver{ + r := &resolver.Resolver{ DAG: n.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/commands/unixfs/ls.go b/core/commands/unixfs/ls.go index 952b212e4..9cf05f610 100644 --- a/core/commands/unixfs/ls.go +++ b/core/commands/unixfs/ls.go @@ -7,15 +7,17 @@ import ( "sort" "text/tabwriter" + cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" + cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" e "github.com/ipfs/go-ipfs/core/commands/e" merkledag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" unixfs "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" unixfspb "github.com/ipfs/go-ipfs/unixfs/pb" - cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" ) type LsLink struct { @@ -91,7 +93,7 @@ possible, please use 'ipfs ls' instead. for _, fpath := range paths { ctx := req.Context() - resolver := &path.Resolver{ + resolver := &resolver.Resolver{ DAG: node.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/core.go b/core/core.go index 5421e086a..54c2b6f45 100644 --- a/core/core.go +++ b/core/core.go @@ -33,7 +33,7 @@ import ( namesys "github.com/ipfs/go-ipfs/namesys" ipnsrp "github.com/ipfs/go-ipfs/namesys/republisher" p2p "github.com/ipfs/go-ipfs/p2p" - path "github.com/ipfs/go-ipfs/path" + "github.com/ipfs/go-ipfs/path/resolver" pin "github.com/ipfs/go-ipfs/pin" repo "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" @@ -119,7 +119,7 @@ type IpfsNode struct { GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc Blocks bserv.BlockService // the block service, get/add blocks. DAG ipld.DAGService // the merkle dag service, get/add objects. - Resolver *path.Resolver // the path resolution system + Resolver *resolver.Resolver // the path resolution system Reporter metrics.Reporter Discovery discovery.Service FilesRoot *mfs.Root diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go index bccb330cd..c34bccb36 100644 --- a/core/coreapi/coreapi.go +++ b/core/coreapi/coreapi.go @@ -7,6 +7,7 @@ import ( coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" namesys "github.com/ipfs/go-ipfs/namesys" ipfspath "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" uio "github.com/ipfs/go-ipfs/unixfs/io" cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid" @@ -87,7 +88,7 @@ func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSyste return p, nil } - r := &ipfspath.Resolver{ + r := &resolver.Resolver{ DAG: ng, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index fed287594..842d30d46 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -19,6 +19,7 @@ import ( dag "github.com/ipfs/go-ipfs/merkledag" dagutils "github.com/ipfs/go-ipfs/merkledag/utils" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" ft "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" @@ -445,7 +446,7 @@ func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) { var newcid *cid.Cid rnode, err := core.Resolve(ctx, i.node.Namesys, i.node.Resolver, rootPath) switch ev := err.(type) { - case path.ErrNoLink: + case resolver.ErrNoLink: // ev.Node < node where resolve failed // ev.Name < new link // but we need to patch from the root @@ -599,7 +600,7 @@ func (i *gatewayHandler) addUserHeaders(w http.ResponseWriter) { } func webError(w http.ResponseWriter, message string, err error, defaultCode int) { - if _, ok := err.(path.ErrNoLink); ok { + if _, ok := err.(resolver.ErrNoLink); ok { webErrorWithCode(w, message, err, http.StatusNotFound) } else if err == routing.ErrNotFound { webErrorWithCode(w, message, err, http.StatusNotFound) diff --git a/core/corerepo/pinning.go b/core/corerepo/pinning.go index 9a6522cdd..d3d3c6858 100644 --- a/core/corerepo/pinning.go +++ b/core/corerepo/pinning.go @@ -19,6 +19,7 @@ import ( "github.com/ipfs/go-ipfs/core" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" uio "github.com/ipfs/go-ipfs/unixfs/io" cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid" @@ -27,7 +28,7 @@ import ( func Pin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) ([]*cid.Cid, error) { out := make([]*cid.Cid, len(paths)) - r := &path.Resolver{ + r := &resolver.Resolver{ DAG: n.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } @@ -60,7 +61,7 @@ func Pin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) func Unpin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) ([]*cid.Cid, error) { unpinned := make([]*cid.Cid, len(paths)) - r := &path.Resolver{ + r := &resolver.Resolver{ DAG: n.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/coreunix/cat.go b/core/coreunix/cat.go index d58f190a3..084d7dee6 100644 --- a/core/coreunix/cat.go +++ b/core/coreunix/cat.go @@ -5,11 +5,12 @@ import ( core "github.com/ipfs/go-ipfs/core" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" uio "github.com/ipfs/go-ipfs/unixfs/io" ) func Cat(ctx context.Context, n *core.IpfsNode, pstr string) (uio.DagReader, error) { - r := &path.Resolver{ + r := &resolver.Resolver{ DAG: n.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } diff --git a/core/pathresolver.go b/core/pathresolver.go index 252ebfa4e..2e873509a 100644 --- a/core/pathresolver.go +++ b/core/pathresolver.go @@ -7,6 +7,7 @@ import ( namesys "github.com/ipfs/go-ipfs/namesys" path "github.com/ipfs/go-ipfs/path" + resolver "github.com/ipfs/go-ipfs/path/resolver" logging "gx/ipfs/QmRb5jh8z2E8hMGN2tkvs1yHynUanqnZ3UeKwgN1i9P1F8/go-log" cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid" @@ -21,7 +22,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 node. -func Resolve(ctx context.Context, nsys namesys.NameSystem, r *path.Resolver, p path.Path) (ipld.Node, error) { +func Resolve(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver, p path.Path) (ipld.Node, error) { if strings.HasPrefix(p.String(), "/ipns/") { evt := log.EventBegin(ctx, "resolveIpnsPath") defer evt.Done() @@ -70,7 +71,7 @@ func Resolve(ctx context.Context, nsys namesys.NameSystem, r *path.Resolver, p p // It first checks if the path is already in the form of just a cid ( or // /ipfs/) and returns immediately if so. Otherwise, it falls back onto // Resolve to perform resolution of the dagnode being referenced. -func ResolveToCid(ctx context.Context, nsys namesys.NameSystem, r *path.Resolver, p path.Path) (*cid.Cid, error) { +func ResolveToCid(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver, p path.Path) (*cid.Cid, error) { // If the path is simply a cid, parse and return it. Parsed paths are already // normalized (read: prepended with /ipfs/ if needed), so segment[1] should diff --git a/path/path.go b/path/path.go index aeaeb5c7a..924aa5dc1 100644 --- a/path/path.go +++ b/path/path.go @@ -9,8 +9,15 @@ import ( cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid" ) -// ErrBadPath is returned when a given path is incorrectly formatted -var ErrBadPath = errors.New("invalid 'ipfs ref' path") +var ( + // ErrBadPath is returned when a given path is incorrectly formatted + ErrBadPath = errors.New("invalid 'ipfs ref' path") + + // ErrNoComponents is used when Paths after a protocol + // do not contain at least one component + ErrNoComponents = errors.New( + "path must contain at least one component") +) // A Path represents an ipfs content path: // * //path/to/file @@ -149,3 +156,25 @@ func Join(pths []string) string { func SplitList(pth string) []string { return strings.Split(pth, "/") } + +// SplitAbsPath clean up and split fpath. It extracts the first component (which +// must be a Multihash) and return it separately. +func SplitAbsPath(fpath Path) (*cid.Cid, []string, error) { + parts := fpath.Segments() + if parts[0] == "ipfs" { + parts = parts[1:] + } + + // if nothing, bail. + if len(parts) == 0 { + return nil, nil, ErrNoComponents + } + + c, err := cid.Decode(parts[0]) + // first element in the path is a cid + if err != nil { + return nil, nil, err + } + + return c, parts[1:], nil +} diff --git a/path/resolver.go b/path/resolver/resolver.go similarity index 83% rename from path/resolver.go rename to path/resolver/resolver.go index 64bdbf752..203fe9ce9 100644 --- a/path/resolver.go +++ b/path/resolver/resolver.go @@ -1,5 +1,5 @@ -// Package path implements utilities for resolving paths within ipfs. -package path +// Package resolver implements utilities for resolving paths within ipfs. +package resolver import ( "context" @@ -8,13 +8,14 @@ import ( "time" dag "github.com/ipfs/go-ipfs/merkledag" + path "github.com/ipfs/go-ipfs/path" logging "gx/ipfs/QmRb5jh8z2E8hMGN2tkvs1yHynUanqnZ3UeKwgN1i9P1F8/go-log" cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid" ipld "gx/ipfs/Qme5bWv7wtjUNGsK2BNGVUFPKiuxWrsqrtvYwCLRw8YFES/go-ipld-format" ) -var log = logging.Logger("path") +var log = logging.Logger("pathresolv") // ErrNoComponents is used when Paths after a protocol // do not contain at least one component @@ -51,36 +52,10 @@ func NewBasicResolver(ds ipld.DAGService) *Resolver { } } -// SplitAbsPath clean up and split fpath. It extracts the first component (which -// must be a Multihash) and return it separately. -func SplitAbsPath(fpath Path) (*cid.Cid, []string, error) { - - log.Debugf("Resolve: '%s'", fpath) - - parts := fpath.Segments() - if parts[0] == "ipfs" { - parts = parts[1:] - } - - // if nothing, bail. - if len(parts) == 0 { - return nil, nil, ErrNoComponents - } - - c, err := cid.Decode(parts[0]) - // first element in the path is a cid - if err != nil { - log.Debug("given path element is not a cid.\n") - return nil, nil, err - } - - return c, parts[1:], nil -} - // ResolveToLastNode walks the given path and returns the ipld.Node // referenced by the last element in it. -func (r *Resolver) ResolveToLastNode(ctx context.Context, fpath Path) (ipld.Node, []string, error) { - c, p, err := SplitAbsPath(fpath) +func (r *Resolver) ResolveToLastNode(ctx context.Context, fpath path.Path) (ipld.Node, []string, error) { + c, p, err := path.SplitAbsPath(fpath) if err != nil { return nil, nil, err } @@ -114,7 +89,7 @@ func (r *Resolver) ResolveToLastNode(ctx context.Context, fpath Path) (ipld.Node // ResolvePath fetches the node for given path. It returns the last item // returned by ResolvePathComponents. -func (r *Resolver) ResolvePath(ctx context.Context, fpath Path) (ipld.Node, error) { +func (r *Resolver) ResolvePath(ctx context.Context, fpath path.Path) (ipld.Node, error) { // validate path if err := fpath.IsValid(); err != nil { return nil, err @@ -136,11 +111,11 @@ func ResolveSingle(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names // ResolvePathComponents fetches the nodes for each segment of the given path. // It uses the first path component as a hash (key) of the first node, then // resolves all other components walking the links, with ResolveLinks. -func (r *Resolver) ResolvePathComponents(ctx context.Context, fpath Path) ([]ipld.Node, error) { +func (r *Resolver) ResolvePathComponents(ctx context.Context, fpath path.Path) ([]ipld.Node, error) { evt := log.EventBegin(ctx, "resolvePathComponents", logging.LoggableMap{"fpath": fpath}) defer evt.Done() - h, parts, err := SplitAbsPath(fpath) + h, parts, err := path.SplitAbsPath(fpath) if err != nil { evt.Append(logging.LoggableMap{"error": err.Error()}) return nil, err diff --git a/path/resolver_test.go b/path/resolver/resolver_test.go similarity index 92% rename from path/resolver_test.go rename to path/resolver/resolver_test.go index d741bbcf1..79a857cb6 100644 --- a/path/resolver_test.go +++ b/path/resolver/resolver_test.go @@ -1,4 +1,4 @@ -package path_test +package resolver_test import ( "context" @@ -8,6 +8,7 @@ import ( merkledag "github.com/ipfs/go-ipfs/merkledag" dagmock "github.com/ipfs/go-ipfs/merkledag/test" path "github.com/ipfs/go-ipfs/path" + "github.com/ipfs/go-ipfs/path/resolver" util "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util" ipld "gx/ipfs/Qme5bWv7wtjUNGsK2BNGVUFPKiuxWrsqrtvYwCLRw8YFES/go-ipld-format" @@ -53,7 +54,7 @@ func TestRecurivePathResolution(t *testing.T) { t.Fatal(err) } - resolver := path.NewBasicResolver(dagService) + resolver := resolver.NewBasicResolver(dagService) node, err := resolver.ResolvePath(ctx, p) if err != nil { t.Fatal(err)