11 "git.curoverse.com/arvados.git/sdk/go/manifest"
21 type keepClient interface {
22 ManifestFileReader(manifest.Manifest, string) (File, error)
25 type collectionFile struct {
27 collection *Collection
32 func (cf *collectionFile) Size() int64 {
36 func (cf *collectionFile) Readdir(count int) ([]os.FileInfo, error) {
40 func (cf *collectionFile) Stat() (os.FileInfo, error) {
41 return collectionDirent{
42 collection: cf.collection,
49 type collectionDir struct {
50 collection *Collection
55 // Readdir implements os.File.
56 func (cd *collectionDir) Readdir(count int) ([]os.FileInfo, error) {
61 } else if len(ret) == 0 {
65 if count >= len(ret) {
69 cd.dirents = cd.dirents[count:]
70 return ret[:count], err
73 // Stat implements os.File.
74 func (cd *collectionDir) Stat() (os.FileInfo, error) {
75 return collectionDirent{
76 collection: cd.collection,
77 name: path.Base(cd.stream),
79 size: int64(len(cd.dirents)),
83 // Close implements os.File.
84 func (cd *collectionDir) Close() error {
88 // Read implements os.File.
89 func (cd *collectionDir) Read([]byte) (int, error) {
93 // Seek implements os.File.
94 func (cd *collectionDir) Seek(int64, int) (int64, error) {
98 // collectionDirent implements os.FileInfo.
99 type collectionDirent struct {
100 collection *Collection
107 // Name implements os.FileInfo.
108 func (e collectionDirent) Name() string {
112 // ModTime implements os.FileInfo.
113 func (e collectionDirent) ModTime() time.Time {
114 if e.collection.ModifiedAt == nil {
117 return *e.collection.ModifiedAt
120 // Mode implements os.FileInfo.
121 func (e collectionDirent) Mode() os.FileMode {
129 // IsDir implements os.FileInfo.
130 func (e collectionDirent) IsDir() bool {
134 // Size implements os.FileInfo.
135 func (e collectionDirent) Size() int64 {
139 // Sys implements os.FileInfo.
140 func (e collectionDirent) Sys() interface{} {
144 // collectionFS implements http.FileSystem.
145 type collectionFS struct {
146 collection *Collection
151 // FileSystem returns an http.FileSystem for the collection.
152 func (c *Collection) FileSystem(client *Client, kc keepClient) http.FileSystem {
153 return &collectionFS{
160 func (c *collectionFS) Open(name string) (http.File, error) {
161 // Ensure name looks the way it does in a manifest.
162 name = path.Clean("/" + name)
163 if name == "/" || name == "./" {
165 } else if strings.HasPrefix(name, "/") {
169 m := manifest.Manifest{Text: c.collection.ManifestText}
171 filesizes := c.fileSizes()
173 // Return a file if it exists.
174 if size, ok := filesizes[name]; ok {
175 reader, err := c.kc.ManifestFileReader(m, name)
179 return &collectionFile{
181 collection: c.collection,
182 name: path.Base(name),
187 // Return a directory if it's the root dir or there are file
189 children := map[string]collectionDirent{}
190 for fnm, size := range filesizes {
191 if !strings.HasPrefix(fnm, name+"/") {
195 ent := fnm[len(name)+1:]
196 if i := strings.Index(ent, "/"); i >= 0 {
201 e.collection = c.collection
207 if len(children) == 0 && name != "." {
208 return nil, os.ErrNotExist
210 dirents := make([]os.FileInfo, 0, len(children))
211 for _, ent := range children {
212 dirents = append(dirents, ent)
214 return &collectionDir{
215 collection: c.collection,
221 // fileSizes returns a map of files that can be opened. Each key
223 func (c *collectionFS) fileSizes() map[string]int64 {
224 var sizes map[string]int64
225 m := manifest.Manifest{Text: c.collection.ManifestText}
226 for ms := range m.StreamIter() {
227 for _, fss := range ms.FileStreamSegments {
229 sizes = map[string]int64{}
231 sizes[ms.StreamName+"/"+fss.Name] += int64(fss.SegLen)