-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathlist.go
128 lines (116 loc) · 3.45 KB
/
list.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
package storage
import (
"context"
"github.com/pkg/errors"
"github.com/viant/afs/asset"
"github.com/viant/afs/matcher"
"github.com/viant/afs/storage"
"github.com/viant/endly"
"github.com/viant/endly/model/location"
"github.com/viant/endly/service/system/storage/copy"
"github.com/viant/endly/service/testing/validator"
"io/ioutil"
)
// DownloadRequest represents a resources Download request, it downloads source into context.state target key
type ListRequest struct {
Source *location.Resource `required:"true" description:"source asset or directory"`
Match *copy.Matcher
Content bool
Recursive bool
Expect interface{}
}
// DownloadResponse represents a Download response
type ListResponse struct {
URL string
Assets []*asset.Resource
Assert *validator.AssertResponse
}
// Remove removes supplied assets
func (s *service) List(context *endly.Context, request *ListRequest) (*ListResponse, error) {
var response = &ListResponse{
Assets: make([]*asset.Resource, 0),
}
return response, s.list(context, request, response)
}
func (s *service) list(context *endly.Context, request *ListRequest, response *ListResponse) error {
options, err := getMatcherOptions(request)
if err != nil {
return err
}
source, storageOpts, err := GetResourceWithOptions(context, request.Source, options...)
if err != nil {
return err
}
response.URL = source.URL
if err = listResource(context.Background(), source.URL, storageOpts, request, response); err != nil {
return err
}
if request.Expect != nil {
response.Assert, err = validator.Assert(context, request, request.Expect, response.Assets, "List", "assert list responses")
}
return nil
}
func listResource(ctx context.Context, URL string, storageOptions []storage.Option, request *ListRequest, response *ListResponse) error {
objects, err := fs.List(context.Background(), URL, storageOptions...)
if err != nil {
return err
}
for i, object := range objects {
var resource *asset.Resource
if object.IsDir() {
if i == 0 {
continue
}
resource = asset.NewDir(object.URL(), object.Mode())
} else {
resource = asset.NewFile(object.URL(), nil, object.Mode())
}
if request.Content && !object.IsDir() {
reader, err := fs.Open(context.Background(), object)
if err != nil {
return errors.Wrapf(err, "failed to download listed content %v", object.URL())
}
resource.Data, err = ioutil.ReadAll(reader)
_ = reader.Close()
if err != nil {
return errors.Wrapf(err, "failed to read listed content %v", object.URL())
}
}
response.Assets = append(response.Assets, resource)
}
if request.Recursive {
dirMatcher := &matcher.Basic{Directory: &request.Recursive}
recursiveOptions := append(storageOptions, dirMatcher.Match)
objects, err := fs.List(ctx, URL, recursiveOptions...)
if err != nil {
return err
}
for i, object := range objects {
if i == 0 {
continue
}
if err = listResource(context.Background(), object.URL(), storageOptions, request, response); err != nil {
return err
}
}
}
return nil
}
func getMatcherOptions(request *ListRequest) ([]storage.Option, error) {
var options = make([]storage.Option, 0)
if request.Match != nil {
matcher, err := request.Match.Matcher()
if err != nil {
return nil, err
}
options = append(options, matcher)
}
return options, nil
}
// Validate checks if request is valid
func (r *ListRequest) Validate() error {
if r.Source == nil {
return errors.New("source was empty")
}
return nil
}