-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfs.go
133 lines (117 loc) · 4.35 KB
/
fs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package qfs
import (
"context"
"errors"
"path/filepath"
"strings"
logger "github.com/ipfs/go-log"
)
var (
log = logger.Logger("qfs")
// ErrNotFound is the canonical error for not finding a value
ErrNotFound = errors.New("path not found")
// ErrReadOnly is a sentinel value for Filesystems that aren't writable
ErrReadOnly = errors.New("readonly filesystem")
)
// PathResolver is the "get" portion of a Filesystem
type PathResolver interface {
Get(ctx context.Context, path string) (File, error)
}
// Filesystem abstracts & unifies filesystem-like behaviour
type Filesystem interface {
// Type returns a string identifier that distinguishes a filesystem from
// all other implementations, example identifiers include: "local", "ipfs",
// and "http"
// types are used as path prefixes when multiplexing filesystems
Type() string
// Has returns whether the `path` is mapped to a value.
// In some contexts, it may be much cheaper only to check for existence of
// a value, rather than retrieving the value itself. (e.g. HTTP HEAD).
// The default implementation is found in `GetBackedHas`.
Has(ctx context.Context, path string) (exists bool, err error)
// Get fetching files and directories from path strings.
// in practice path strings can be things like:
// * a local filesystem
// * URLS (a "URL path resolver") or
// * content-addressed file systems like IPFS or Git
// Datasets & dataset components use a filesource to resolve string references
Get(ctx context.Context, path string) (File, error)
// Put places a file or directory on the filesystem, returning the root path.
// The returned path may or may not honor the path of the given file
Put(ctx context.Context, file File) (path string, err error)
// Delete removes a file or directory from the filesystem
Delete(ctx context.Context, path string) (err error)
}
// Config binds a filesystem type to a configuration map
type Config struct {
Type string `json:"type"`
Config map[string]interface{} `json:"config,omitempty"`
}
// Constructor is a function that creates a filesystem from a config map
// the passed in context should last for the duration of the existence of the
// store. Any resources allocated by the store should be scoped to this context
type Constructor func(ctx context.Context, cfg map[string]interface{}) (Filesystem, error)
// ReleasingFilesystem provides a channel to signal cleanup is finished. It
// sends after a filesystem has closed & about to release all it's resources
type ReleasingFilesystem interface {
Filesystem
Done() <-chan struct{}
DoneErr() error
}
// Destroyer is an optional interface to tear down a filesystem, removing all
// persisted resources
type Destroyer interface {
Destroy() error
}
// PinningFS interface for content stores that support the concept of pinnings
type PinningFS interface {
Pin(ctx context.Context, key string, recursive bool) error
Unpin(ctx context.Context, key string, recursive bool) error
}
// CAFS stands for "content-addressed filesystem". Filesystem that implement
// this interface declare that all paths to persisted content are reference-by
// -hash.
// TODO (b5) - write up a spec test suite for CAFS conformance
type CAFS interface {
IsContentAddressedFilesystem()
}
// AbsPath adjusts the provided string to a path lib functions can work with
// because paths for Qri can come from the local filesystem, an http url, or
// the distributed web, Absolutizing is a little tricky
//
// If lib in put params call for a path, running input through AbsPath before
// calling a lib function should help reduce errors. calling AbsPath on empty
// string has no effect
func AbsPath(path *string) (err error) {
if *path == "" {
return
}
*path = strings.TrimSpace(*path)
p := *path
// bail on urls and ipfs hashes
pk := PathKind(p)
if pk == "http" || pk == "ipfs" {
return
}
// TODO (b5) - perform tilda (~) expansion
if filepath.IsAbs(p) {
return
}
*path, err = filepath.Abs(p)
return
}
// PathKind estimates what type of resolver string path is referring to
func PathKind(path string) string {
if path == "" {
return "none"
} else if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
return "http"
} else if strings.HasPrefix(path, "/ipfs") {
return "ipfs"
} else if strings.HasPrefix(path, "/mem") {
return "mem"
} else if strings.HasPrefix(path, "/map") {
return "map"
}
return "local"
}