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