16314: Merge branch 'master'
[arvados.git] / sdk / go / arvados / fs_project.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package arvados
6
7 import (
8         "log"
9         "strings"
10 )
11
12 func (fs *customFileSystem) defaultUUID(uuid string) (string, error) {
13         if uuid != "" {
14                 return uuid, nil
15         }
16         var resp User
17         err := fs.RequestAndDecode(&resp, "GET", "arvados/v1/users/current", nil, nil)
18         if err != nil {
19                 return "", err
20         }
21         return resp.UUID, nil
22 }
23
24 // loadOneChild loads only the named child, if it exists.
25 func (fs *customFileSystem) projectsLoadOne(parent inode, uuid, name string) (inode, error) {
26         uuid, err := fs.defaultUUID(uuid)
27         if err != nil {
28                 return nil, err
29         }
30
31         var contents CollectionList
32         for _, subst := range []string{"/", fs.forwardSlashNameSubstitution} {
33                 contents = CollectionList{}
34                 err = fs.RequestAndDecode(&contents, "GET", "arvados/v1/groups/"+uuid+"/contents", nil, ResourceListParams{
35                         Count: "none",
36                         Filters: []Filter{
37                                 {"name", "=", strings.Replace(name, subst, "/", -1)},
38                                 {"uuid", "is_a", []string{"arvados#collection", "arvados#group"}},
39                                 {"groups.group_class", "=", "project"},
40                         },
41                 })
42                 if err != nil {
43                         return nil, err
44                 }
45                 if len(contents.Items) > 0 || fs.forwardSlashNameSubstitution == "/" || fs.forwardSlashNameSubstitution == "" || !strings.Contains(name, fs.forwardSlashNameSubstitution) {
46                         break
47                 }
48                 // If the requested name contains the configured "/"
49                 // replacement string and didn't match a
50                 // project/collection exactly, we'll try again with
51                 // "/" in its place, so a lookup of a munged name
52                 // works regardless of whether the directory listing
53                 // has been populated with escaped names.
54                 //
55                 // Note this doesn't handle items whose names contain
56                 // both "/" and the substitution string.
57         }
58         if len(contents.Items) == 0 {
59                 return nil, nil
60         }
61         coll := contents.Items[0]
62
63         if strings.Contains(coll.UUID, "-j7d0g-") {
64                 // Group item was loaded into a Collection var -- but
65                 // we only need the Name and UUID anyway, so it's OK.
66                 return fs.newProjectNode(parent, coll.Name, coll.UUID), nil
67         } else if strings.Contains(coll.UUID, "-4zz18-") {
68                 return deferredCollectionFS(fs, parent, coll), nil
69         } else {
70                 log.Printf("projectnode: unrecognized UUID in response: %q", coll.UUID)
71                 return nil, ErrInvalidArgument
72         }
73 }
74
75 func (fs *customFileSystem) projectsLoadAll(parent inode, uuid string) ([]inode, error) {
76         uuid, err := fs.defaultUUID(uuid)
77         if err != nil {
78                 return nil, err
79         }
80
81         var inodes []inode
82
83         // Note: the "filters" slice's backing array might be reused
84         // by append(filters,...) below. This isn't goroutine safe,
85         // but all accesses are in the same goroutine, so it's OK.
86         filters := []Filter{{"owner_uuid", "=", uuid}}
87         params := ResourceListParams{
88                 Count:   "none",
89                 Filters: filters,
90                 Order:   "uuid",
91         }
92         for {
93                 var resp CollectionList
94                 err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/collections", nil, params)
95                 if err != nil {
96                         return nil, err
97                 }
98                 if len(resp.Items) == 0 {
99                         break
100                 }
101                 for _, i := range resp.Items {
102                         coll := i
103                         if fs.forwardSlashNameSubstitution != "" {
104                                 coll.Name = strings.Replace(coll.Name, "/", fs.forwardSlashNameSubstitution, -1)
105                         }
106                         if !permittedName(coll.Name) {
107                                 continue
108                         }
109                         inodes = append(inodes, deferredCollectionFS(fs, parent, coll))
110                 }
111                 params.Filters = append(filters, Filter{"uuid", ">", resp.Items[len(resp.Items)-1].UUID})
112         }
113
114         filters = append(filters, Filter{"group_class", "=", "project"})
115         params.Filters = filters
116         for {
117                 var resp GroupList
118                 err = fs.RequestAndDecode(&resp, "GET", "arvados/v1/groups", nil, params)
119                 if err != nil {
120                         return nil, err
121                 }
122                 if len(resp.Items) == 0 {
123                         break
124                 }
125                 for _, group := range resp.Items {
126                         if fs.forwardSlashNameSubstitution != "" {
127                                 group.Name = strings.Replace(group.Name, "/", fs.forwardSlashNameSubstitution, -1)
128                         }
129                         if !permittedName(group.Name) {
130                                 continue
131                         }
132                         inodes = append(inodes, fs.newProjectNode(parent, group.Name, group.UUID))
133                 }
134                 params.Filters = append(filters, Filter{"uuid", ">", resp.Items[len(resp.Items)-1].UUID})
135         }
136         return inodes, nil
137 }