path.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package path
  2. import (
  3. "errors"
  4. "path"
  5. "strings"
  6. "github.com/ipfs/go-cid"
  7. mh "github.com/multiformats/go-multihash"
  8. )
  9. // ErrBadPath is returned when a given path is incorrectly formatted
  10. var ErrBadPath = errors.New("invalid ipfs ref path")
  11. // TODO: debate making this a private struct wrapped in a public interface
  12. // would allow us to control creation, and cache segments.
  13. type Path string
  14. // FromString safely converts a string type to a Path type
  15. func FromString(s string) Path {
  16. return Path(s)
  17. }
  18. func (p Path) Segments() []string {
  19. cleaned := path.Clean(string(p))
  20. segments := strings.Split(cleaned, "/")
  21. // Ignore leading slash
  22. if len(segments[0]) == 0 {
  23. segments = segments[1:]
  24. }
  25. return segments
  26. }
  27. func (p Path) String() string {
  28. return string(p)
  29. }
  30. // FromCid safely converts a cid.Cid type to a Path type
  31. func FromCid(c *cid.Cid) Path {
  32. return Path("/ipfs/" + c.String())
  33. }
  34. func FromSegments(prefix string, seg ...string) (Path, error) {
  35. return ParsePath(prefix + strings.Join(seg, "/"))
  36. }
  37. func ParsePath(txt string) (Path, error) {
  38. parts := strings.Split(txt, "/")
  39. if len(parts) == 1 {
  40. kp, err := ParseCidToPath(txt)
  41. if err == nil {
  42. return kp, nil
  43. }
  44. }
  45. // if the path doesnt being with a '/'
  46. // we expect this to start with a hash, and be an 'ipfs' path
  47. if parts[0] != "" {
  48. if _, err := ParseCidToPath(parts[0]); err != nil {
  49. return "", ErrBadPath
  50. }
  51. // The case when the path starts with hash without a protocol prefix
  52. return Path("/ipfs/" + txt), nil
  53. }
  54. if len(parts) < 3 {
  55. return "", ErrBadPath
  56. }
  57. if parts[1] == "ipfs" {
  58. if _, err := ParseCidToPath(parts[2]); err != nil {
  59. return "", err
  60. }
  61. } else if parts[1] != "ipns" {
  62. return "", ErrBadPath
  63. }
  64. return Path(txt), nil
  65. }
  66. func ParseCidToPath(txt string) (Path, error) {
  67. if txt == "" {
  68. return "", ErrNoComponents
  69. }
  70. c, err := cid.Decode(txt)
  71. if err != nil {
  72. return "", err
  73. }
  74. return FromCid(&c), nil
  75. }
  76. func (p *Path) IsValid() error {
  77. _, err := ParsePath(p.String())
  78. return err
  79. }
  80. // Paths after a protocol must contain at least one component
  81. var ErrNoComponents = errors.New(
  82. "path must contain at least one component")
  83. // ErrNoLink is returned when a link is not found in a path
  84. type ErrNoLink struct {
  85. Name string
  86. Node mh.Multihash
  87. }