Commit c13536f1 authored by Steven Allen's avatar Steven Allen

include the path in path errors

This should improve UX by telling the user the path we failed to parse.
parent a1e7a849
package path
import (
"fmt"
)
// helper type so path parsing errors include the path
type pathError struct {
error error
path string
}
func (e *pathError) Error() string {
return fmt.Sprintf("invalid path %q: %s", e.path, e.error)
}
func (e *pathError) Unwrap() error {
return e.error
}
func (e *pathError) Path() string {
return e.path
}
...@@ -2,23 +2,13 @@ ...@@ -2,23 +2,13 @@
package path package path
import ( import (
"errors" "fmt"
"path" "path"
"strings" "strings"
cid "github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
) )
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: // A Path represents an ipfs content path:
// * /<cid>/path/to/file // * /<cid>/path/to/file
// * /ipfs/<cid> // * /ipfs/<cid>
...@@ -107,33 +97,33 @@ func ParsePath(txt string) (Path, error) { ...@@ -107,33 +97,33 @@ func ParsePath(txt string) (Path, error) {
// we expect this to start with a hash, and be an 'ipfs' path // we expect this to start with a hash, and be an 'ipfs' path
if parts[0] != "" { if parts[0] != "" {
if _, err := cid.Decode(parts[0]); err != nil { if _, err := cid.Decode(parts[0]); err != nil {
return "", ErrBadPath return "", &pathError{error: err, path: txt}
} }
// The case when the path starts with hash without a protocol prefix // The case when the path starts with hash without a protocol prefix
return Path("/ipfs/" + txt), nil return Path("/ipfs/" + txt), nil
} }
if len(parts) < 3 { if len(parts) < 3 {
return "", ErrBadPath return "", &pathError{error: fmt.Errorf("path does not begin with '/'"), path: txt}
} }
//TODO: make this smarter //TODO: make this smarter
switch parts[1] { switch parts[1] {
case "ipfs", "ipld": case "ipfs", "ipld":
if parts[2] == "" { if parts[2] == "" {
return "", ErrNoComponents return "", &pathError{error: fmt.Errorf("not enough path components"), path: txt}
} }
// Validate Cid. // Validate Cid.
_, err := cid.Decode(parts[2]) _, err := cid.Decode(parts[2])
if err != nil { if err != nil {
return "", err return "", &pathError{error: fmt.Errorf("invalid CID: %s", err), path: txt}
} }
case "ipns": case "ipns":
if parts[2] == "" { if parts[2] == "" {
return "", ErrNoComponents return "", &pathError{error: fmt.Errorf("not enough path components"), path: txt}
} }
default: default:
return "", ErrBadPath return "", &pathError{error: fmt.Errorf("unknown namespace %q", parts[1]), path: txt}
} }
return Path(txt), nil return Path(txt), nil
...@@ -142,12 +132,12 @@ func ParsePath(txt string) (Path, error) { ...@@ -142,12 +132,12 @@ func ParsePath(txt string) (Path, error) {
// ParseCidToPath takes a CID in string form and returns a valid ipfs Path. // ParseCidToPath takes a CID in string form and returns a valid ipfs Path.
func ParseCidToPath(txt string) (Path, error) { func ParseCidToPath(txt string) (Path, error) {
if txt == "" { if txt == "" {
return "", ErrNoComponents return "", &pathError{error: fmt.Errorf("empty"), path: txt}
} }
c, err := cid.Decode(txt) c, err := cid.Decode(txt)
if err != nil { if err != nil {
return "", err return "", &pathError{error: err, path: txt}
} }
return FromCid(c), nil return FromCid(c), nil
...@@ -179,13 +169,13 @@ func SplitAbsPath(fpath Path) (cid.Cid, []string, error) { ...@@ -179,13 +169,13 @@ func SplitAbsPath(fpath Path) (cid.Cid, []string, error) {
// if nothing, bail. // if nothing, bail.
if len(parts) == 0 { if len(parts) == 0 {
return cid.Cid{}, nil, ErrNoComponents return cid.Cid{}, nil, &pathError{error: fmt.Errorf("empty"), path: string(fpath)}
} }
c, err := cid.Decode(parts[0]) c, err := cid.Decode(parts[0])
// first element in the path is a cid // first element in the path is a cid
if err != nil { if err != nil {
return cid.Cid{}, nil, err return cid.Cid{}, nil, &pathError{error: fmt.Errorf("invalid CID: %s", err), path: string(fpath)}
} }
return c, parts[1:], nil return c, parts[1:], nil
......
package path package path
import ( import (
"strings"
"testing" "testing"
) )
...@@ -44,8 +45,8 @@ func TestNoComponents(t *testing.T) { ...@@ -44,8 +45,8 @@ func TestNoComponents(t *testing.T) {
"/ipld/", "/ipld/",
} { } {
_, err := ParsePath(s) _, err := ParsePath(s)
if err != ErrNoComponents { if err == nil || !strings.Contains(err.Error(), "not enough path components") || !strings.Contains(err.Error(), s) {
t.Errorf("expected ErrNoComponents, got %s", err) t.Error("wrong error")
} }
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment