X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/f5d919c7e7bcf46e245a4459f3393022ff471db0..50f8d8487ad5156058087438b670d7c6f8a8d718:/sdk/go/arvados/fs_project.go diff --git a/sdk/go/arvados/fs_project.go b/sdk/go/arvados/fs_project.go index 4dd869910c..92995510c7 100644 --- a/sdk/go/arvados/fs_project.go +++ b/sdk/go/arvados/fs_project.go @@ -7,50 +7,89 @@ package arvados import ( "log" "os" - "sync" + "strings" ) -// projectnode exposes an Arvados project as a filesystem directory. -type projectnode struct { - inode - uuid string - setupOnce sync.Once - err error +func (fs *customFileSystem) defaultUUID(uuid string) (string, error) { + if uuid != "" { + return uuid, nil + } + var resp User + err := fs.RequestAndDecode(&resp, "GET", "arvados/v1/users/current", nil, nil) + if err != nil { + return "", err + } + return resp.UUID, nil } -func (pn *projectnode) setup() { - fs := pn.FS().(*siteFileSystem) - if pn.uuid == "" { - var resp User - pn.err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/users/current", nil, nil) - if pn.err != nil { - return - } - pn.uuid = resp.UUID +// loadOneChild loads only the named child, if it exists. +func (fs *customFileSystem) projectsLoadOne(parent inode, uuid, name string) (inode, error) { + uuid, err := fs.defaultUUID(uuid) + if err != nil { + return nil, err + } + + var contents CollectionList + err = fs.RequestAndDecode(&contents, "GET", "arvados/v1/groups/"+uuid+"/contents", nil, ResourceListParams{ + Count: "none", + Filters: []Filter{ + {"name", "=", name}, + {"uuid", "is_a", []string{"arvados#collection", "arvados#group"}}, + {"groups.group_class", "=", "project"}, + }, + }) + if err != nil { + return nil, err + } + if len(contents.Items) == 0 { + return nil, os.ErrNotExist + } + coll := contents.Items[0] + + if strings.Contains(coll.UUID, "-j7d0g-") { + // Group item was loaded into a Collection var -- but + // we only need the Name and UUID anyway, so it's OK. + return fs.newProjectNode(parent, coll.Name, coll.UUID), nil + } else if strings.Contains(coll.UUID, "-4zz18-") { + return deferredCollectionFS(fs, parent, coll), nil + } else { + log.Printf("projectnode: unrecognized UUID in response: %q", coll.UUID) + return nil, ErrInvalidArgument + } +} + +func (fs *customFileSystem) projectsLoadAll(parent inode, uuid string) ([]inode, error) { + uuid, err := fs.defaultUUID(uuid) + if err != nil { + return nil, err } - filters := []Filter{{"owner_uuid", "=", pn.uuid}} + + var inodes []inode + + // Note: the "filters" slice's backing array might be reused + // by append(filters,...) below. This isn't goroutine safe, + // but all accesses are in the same goroutine, so it's OK. + filters := []Filter{{"owner_uuid", "=", uuid}} params := ResourceListParams{ + Count: "none", Filters: filters, Order: "uuid", } for { var resp CollectionList - pn.err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/collections", nil, params) - if pn.err != nil { - // TODO: retry on next access, instead of returning the same error forever - return + err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/collections", nil, params) + if err != nil { + return nil, err } if len(resp.Items) == 0 { break } for _, i := range resp.Items { coll := i - if coll.Name == "" { + if !permittedName(coll.Name) { continue } - pn.inode.Child(coll.Name, func(inode) inode { - return deferredCollectionFS(fs, pn, coll) - }) + inodes = append(inodes, deferredCollectionFS(fs, parent, coll)) } params.Filters = append(filters, Filter{"uuid", ">", resp.Items[len(resp.Items)-1].UUID}) } @@ -59,55 +98,20 @@ func (pn *projectnode) setup() { params.Filters = filters for { var resp GroupList - pn.err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/groups", nil, params) - if pn.err != nil { - // TODO: retry on next access, instead of returning the same error forever - return + err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/groups", nil, params) + if err != nil { + return nil, err } if len(resp.Items) == 0 { break } for _, group := range resp.Items { - if group.Name == "" || group.Name == "." || group.Name == ".." { + if !permittedName(group.Name) { continue } - pn.inode.Child(group.Name, func(inode) inode { - return fs.newProjectNode(pn, group.Name, group.UUID) - }) + inodes = append(inodes, fs.newProjectNode(parent, group.Name, group.UUID)) } params.Filters = append(filters, Filter{"uuid", ">", resp.Items[len(resp.Items)-1].UUID}) } -} - -func (pn *projectnode) Readdir() []os.FileInfo { - pn.setupOnce.Do(pn.setup) - return pn.inode.Readdir() -} - -func (pn *projectnode) Child(name string, replace func(inode) inode) inode { - pn.setupOnce.Do(pn.setup) - if pn.err != nil { - log.Printf("BUG: not propagating error setting up %T %v: %s", pn, pn, pn.err) - // TODO: propagate error, instead of just being empty - return nil - } - if replace == nil { - // lookup - return pn.inode.Child(name, nil) - } - return pn.inode.Child(name, func(existing inode) inode { - if repl := replace(existing); repl == nil { - // delete - // (TODO) - return pn.Child(name, nil) // not implemented - } else if repl.FileInfo().IsDir() { - // mkdir - // TODO: repl.SetParent(pn, name), etc. - return pn.Child(name, nil) // not implemented - } else { - // create file - // TODO: repl.SetParent(pn, name), etc. - return pn.Child(name, nil) // not implemented - } - }) + return inodes, nil }