This repository was archived by the owner on Mar 14, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathminimal.ncl
More file actions
278 lines (245 loc) · 9.17 KB
/
Copy pathminimal.ncl
File metadata and controls
278 lines (245 loc) · 9.17 KB
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
let Tys = [| 'Builder, 'Path, 'OutputLib, 'OutputBin, 'OutputData, 'Source, 'Local, 'Subset, 'Profile, 'Layer, 'Upstream, 'Test, 'Harness |]
in
let attrs_schema = import "attr_classes.ncl" in
let needs_schema = import "need_classes.ncl" in
let CmdSpec = std.contract.any_of [
String,
Array String,
] in
{
BuildSpec | doc "A minimal build spec, defining inputs to the build as well as outputs which carry build artifacts downstream" = {
ty | Tys = 'Builder,
name
| String,
inputs
| Array Input,
runtime_deps
| Array RuntimeDep | optional,
needs | Needs | optional,
attrs | Attrs | optional,
cmd | CmdSpec | optional,
cmds | Array CmdSpec | optional,
build_args | {_: String} | optional,
# Do NOT set this yourself
__magic_buildspec_id | optional,
prebuilt | Bool | optional,
target | String | optional,
replace_on_cycle | BuildSpec | optional,
outputs
| {_ : Output} | optional = {},
tests | {_: Test} | optional,
},
build | Dyn -> BuildSpec | doc "Constructs a minimal build spec." =
fun spec => spec | BuildSpec,
Output | doc "An artifact produced by the execution of a build spec" = fun Contract =>
std.contract.custom (fun label value =>
match {
{ty = 'OutputLib, ..} => std.contract.check OutputLib label value,
{ty = 'OutputBin, ..} => std.contract.check OutputBin label value,
{ty = 'OutputData, ..} => std.contract.check OutputData label value,
_ => 'Error {
message = "Expected Output type",
},
}
value
),
OutputLib | doc "An output of a build spec which represents a shared library." = {
ty | Tys = 'OutputLib,
glob
| String,
allow_data | Bool | optional,
},
OutputBin | doc "An output of a build spec which represents a binary." = {
ty | Tys = 'OutputBin,
glob
| String,
},
OutputData | doc "An output of a build spec which represents data files that are used during execution." = {
ty | Tys = 'OutputData,
glob
| String,
allow_executable | Bool | optional,
},
RuntimeDep | doc "Possible values for a runtime dependency entry." = fun Contract =>
std.contract.custom (fun label value =>
match {
{ty = 'Builder, ..} => std.contract.check BuildSpec label value,
{ty = 'Subset, ..} => std.contract.check Subset label value,
{ty = 'Upstream, ..} => std.contract.check UpstreamPkg label value,
_ => 'Error {
message = "Expected Input type",
},
}
value
),
Input | doc "Possible inputs to a build spec." = fun Contract =>
std.contract.custom (fun label value =>
match {
{ty = 'Builder, ..} => std.contract.check BuildSpec label value,
{ty = 'Path, ..} => std.contract.check HostPath label value,
{ty = 'Source, ..} => std.contract.check Source label value,
{ty = 'Local, ..} => std.contract.check Local label value,
{ty = 'Subset, ..} => std.contract.check Subset label value,
{ty = 'Upstream, ..} => std.contract.check UpstreamPkg label value,
_ => 'Error {
message = "Expected Input type",
},
}
value
),
HostPath | doc "An input which represents a path on the building machine" = {
ty | Tys = 'Path,
path
| String,
},
Source | doc "An input to a build spec which represents source code from some location." = {
ty | Tys = 'Source,
file
| String | optional,
url
| String | optional,
sha256
| String | optional,
extract
| Bool | optional,
strip_prefix
| String | optional,
},
Local = {
ty | Tys = 'Local,
file
| String,
},
Subset | doc "A dependency on a subset of the outputs from another build spec." = {
ty | Tys = 'Subset,
from
| BuildSpec,
outputs
| Array String,
},
subsetOf | BuildSpec -> Array String -> Subset | doc "Constructs a subset of the outputs of a build, for use as an input or runtime_dep." =
fun spec outputs =>
{from = spec, include outputs} | Subset,
Attrs | doc "A map of attributes applied to a build-spec, which are validated according to attr_classes.ncl."
= std.contract.custom (fun label record_value =>
if !(std.is_record record_value) then
'Error { message = "not a record" }
else
record_value
|> std.record.to_array
|> std.array.try_fold_left
(fun acc { field, value } =>
if std.record.has_field field attrs_schema then
std.contract.check attrs_schema."%{field}".validate label value
|> match {
'Ok wrapped_value => 'Ok (acc @ [{ include field, value = wrapped_value }]),
'Error e => 'Error { message = "failed to validate %{field}", blame_location = e.blame_location }
}
else
'Error { message = "`%{field}` is not a valid attribute" }
)
[]
|> match {
'Ok array => 'Ok (std.record.from_array array),
'Error e => 'Error e,
}
),
Needs | doc "Abstract dependencies needed by a build-spec, which are validated according to need_classes.ncl."
= std.contract.custom (fun label record_value =>
if !(std.is_record record_value) then
'Error { message = "not a record" }
else
record_value
|> std.record.to_array
|> std.array.try_fold_left
(fun acc { field, value } =>
if std.record.has_field field needs_schema then
std.contract.check needs_schema."%{field}".validate label value
|> match {
'Ok wrapped_value => 'Ok (acc @ [{ include field, value = wrapped_value }]),
'Error e => 'Error { message = "failed to validate %{field}", blame_location = e.blame_location }
}
else
'Error { message = "`%{field}` is not a valid need" }
)
[]
|> match {
'Ok array => 'Ok (std.record.from_array array),
'Error e => 'Error e,
}
),
Profile | doc "The initial configuration/wiring for an environment." = {
ty | Tys = 'Profile,
name
| String,
from_profile
| String | optional,
packages
| Array String | optional,
env_vars
| {_ : String} | optional,
# Only one of patch or patches may be set.
patch
| {_: {_ : String}} | optional,
patches
| {_: {_ : String}} | optional,
},
profile | Dyn -> Profile | doc "Constructs a profile." =
fun spec => spec | Profile,
# Intended for internal use
Layer | doc "Implementation detail: the set of build-specs and profiles to be ingested." = {
ty | Tys = 'Layer,
builds | Array BuildSpec,
profiles | Array Profile,
harnesses | Array Harness,
},
layer | Dyn -> Layer | doc "Constructs a layer." =
fun spec => spec | Layer,
UpstreamPkg = {
ty | Tys = 'Upstream,
name | String,
},
upstream | String -> UpstreamPkg | doc "Symbolizes a build with the given name from upstream." =
fun n => {name = n},
Test | doc "A unit test for a decl." = {
ty | Tys = 'Test,
class | [| 'Standalone, 'Build |],
test_deps
| Array RuntimeDep | optional,
cmd | String | optional,
cmds | Array (Array String) | optional,
},
standaloneTest | String -> Test | doc "A test, run using the outputs of the build." =
fun cmd => {
class = 'Standalone,
include cmd,
},
buildTest | String -> Test | doc "A test, run in the build container once the build is completed." =
fun cmd => {
class = 'Build,
include cmd,
},
HarnessMatcherEntry = {
file_regexes | {_ : String} | optional,
},
Harness | doc "A specific way to build a directory of source into software." = {
ty | Tys = 'Harness,
name
| String,
build_packages
| Array String | optional,
runtime_packages
| Array String | optional,
build_env_vars
| {_ : String} | optional,
build_cmd | CmdSpec | optional,
build_cmds_cmd | CmdSpec | optional,
project_matchers | Array HarnessMatcherEntry | optional,
},
harness | Dyn -> Harness | doc "Constructs a harness." =
fun spec => spec | Harness,
Target | doc "A specific system that packages can run on." = {
os | [| 'Linux, 'MacOS |],
arch | [| 'Amd64, 'Arm64 |],
},
}