forked from elastic/package-spec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfolder_item_spec.go
216 lines (174 loc) · 7.04 KB
/
folder_item_spec.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
package specschema
import (
"fmt"
"io/fs"
"reflect"
"github.com/creasty/defaults"
"github.com/elastic/package-spec/v3/code/go/internal/spectypes"
"github.com/elastic/package-spec/v3/code/go/pkg/specerrors"
)
const (
visibilityTypePublic = "public"
visibilityTypePrivate = "private"
)
// ItemSpec implements the `spectype.ItemSpec` interface for a folder item spec.
type ItemSpec struct {
itemSpec *folderItemSpec
}
// MaxTotalContents is the maximum number of files and directories
// inside a directory and its children directories.
func (s *ItemSpec) MaxTotalContents() int {
return s.itemSpec.SpecLimits.TotalContentsLimit
}
// MaxTotalSize is the maximum size of a file, or all the files and
// directories inside a directory.
func (s *ItemSpec) MaxTotalSize() spectypes.FileSize {
return s.itemSpec.SpecLimits.TotalSizeLimit
}
// MaxFileSize is the maximum size of an individual file.
func (s *ItemSpec) MaxFileSize() spectypes.FileSize {
return s.itemSpec.SpecLimits.SizeLimit
}
// MaxConfigurationSize is the maximum size of a configuration file.
func (s *ItemSpec) MaxConfigurationSize() spectypes.FileSize {
return s.itemSpec.SpecLimits.ConfigurationSizeLimit
}
// MaxRelativePathSize is the maximum size of a file indicated with a relative path.
func (s *ItemSpec) MaxRelativePathSize() spectypes.FileSize {
return s.itemSpec.SpecLimits.RelativePathSizeLimit
}
// MaxFieldsPerDataStream is the maxumum number of fields that each data stream can define.
func (s *ItemSpec) MaxFieldsPerDataStream() int {
return s.itemSpec.SpecLimits.FieldsPerDataStreamLimit
}
// AdditionalContents returns true if the item can contain contents not defined in the spec.
func (s *ItemSpec) AdditionalContents() bool {
return s.itemSpec.AdditionalContents
}
// ContentMediaType returns the expected content type of a file.
func (s *ItemSpec) ContentMediaType() *spectypes.ContentType {
return s.itemSpec.ContentMediaType
}
// Contents returns the definitions of the children elements of this item.
func (s *ItemSpec) Contents() []spectypes.ItemSpec {
result := make([]spectypes.ItemSpec, len(s.itemSpec.Contents))
for i := range s.itemSpec.Contents {
result[i] = &ItemSpec{s.itemSpec.Contents[i]}
}
return result
}
// DevelopmentFolder returns true if the item is inside a development folder.
func (s *ItemSpec) DevelopmentFolder() bool {
return s.itemSpec.DevelopmentFolder
}
// AllowLink returns true if the item allows links.
func (s *ItemSpec) AllowLink() bool {
return s.itemSpec.AllowLink
}
// ForbiddenPatterns returns the list of forbidden patterns for the name of this item.
func (s *ItemSpec) ForbiddenPatterns() []string {
return s.itemSpec.ForbiddenPatterns
}
// IsDir returns true if the item is a directory.
func (s *ItemSpec) IsDir() bool {
return s.itemSpec.ItemType == spectypes.ItemTypeFolder
}
// Name returns the name of the item inside its parent.
func (s *ItemSpec) Name() string {
return s.itemSpec.Name
}
// Pattern returns the allowed pattern for the name of this item.
func (s *ItemSpec) Pattern() string {
return s.itemSpec.Pattern
}
// Release returns 'beta' if the item definition is in beta stage.
func (s *ItemSpec) Release() string {
return s.itemSpec.Release
}
// Required returns true if this item must be defined.
func (s *ItemSpec) Required() bool {
return s.itemSpec.Required
}
// Type returns the type of file ('file' or 'folder').
func (s *ItemSpec) Type() string {
return s.itemSpec.ItemType
}
// ValidateSchema validates if the indicated file complies with the schema of the item.
func (s *ItemSpec) ValidateSchema(fsys fs.FS, itemPath string) specerrors.ValidationErrors {
return s.itemSpec.ValidateSchema(fsys, itemPath)
}
type folderItemSpec struct {
Description string `json:"description" yaml:"description"`
ItemType string `json:"type" yaml:"type"`
ContentMediaType *spectypes.ContentType `json:"contentMediaType" yaml:"contentMediaType"`
ForbiddenPatterns []string `json:"forbiddenPatterns" yaml:"forbiddenPatterns"`
Name string `json:"name" yaml:"name"`
Pattern string `json:"pattern" yaml:"pattern"`
Required bool `json:"required" yaml:"required"`
Ref string `json:"$ref" yaml:"$ref"`
Visibility string `json:"visibility" yaml:"visibility" default:"public"`
AdditionalContents bool `json:"additionalContents" yaml:"additionalContents"`
Contents []*folderItemSpec `json:"contents" yaml:"contents"`
DevelopmentFolder bool `json:"developmentFolder" yaml:"developmentFolder"`
AllowLink bool `json:"allowLink" yaml:"allowLink"`
// As it is required to be inline both in yaml and json, this struct must be public embedded field
SpecLimits `yaml:",inline"`
// Release type of the spec: beta, ga.
// Packages using beta features won't be able to go GA.
// Default release: ga
Release string `json:"release" yaml:"release"`
schema spectypes.FileSchema
}
func (s *folderItemSpec) setDefaultValues() error {
err := defaults.Set(s)
if err != nil {
return fmt.Errorf("could not set default values: %w", err)
}
for _, content := range s.Contents {
err = content.setDefaultValues()
if err != nil {
return err
}
}
return nil
}
func (s *folderItemSpec) propagateContentLimits() {
for _, content := range s.Contents {
content.SpecLimits.update(s.SpecLimits)
content.propagateContentLimits()
}
}
// SpecLimits represents limits related to an item
type SpecLimits struct {
// Limit to the total number of elements in a directory.
TotalContentsLimit int `json:"totalContentsLimit" yaml:"totalContentsLimit"`
// Limit to the total size of files in a directory.
TotalSizeLimit spectypes.FileSize `json:"totalSizeLimit" yaml:"totalSizeLimit"`
// Limit to individual files.
SizeLimit spectypes.FileSize `json:"sizeLimit" yaml:"sizeLimit"`
// Limit to individual configuration files (yaml files).
ConfigurationSizeLimit spectypes.FileSize `json:"configurationSizeLimit" yaml:"configurationSizeLimit"`
// Limit to files referenced as relative paths (images).
RelativePathSizeLimit spectypes.FileSize `json:"relativePathSizeLimit" yaml:"relativePathSizeLimit"`
// Maximum number of fields per data stream, can only be set at the root level spec.
FieldsPerDataStreamLimit int `json:"fieldsPerDataStreamLimit" yaml:"fieldsPerDataStreamLimit"`
}
func (l *SpecLimits) update(o SpecLimits) {
target := reflect.ValueOf(l).Elem()
source := reflect.ValueOf(&o).Elem()
for i := 0; i < target.NumField(); i++ {
field := target.Field(i)
if field.IsZero() {
field.Set(source.Field(i))
}
}
}
func (s *folderItemSpec) ValidateSchema(fsys fs.FS, itemPath string) specerrors.ValidationErrors {
if s.schema == nil {
return nil
}
return s.schema.Validate(fsys, itemPath)
}