@platforma-sdk/workflow-tengo 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -3
- package/dist/index.mjs +6 -3
- package/dist/tengo/lib/exec.R.internal.lib.tengo +4 -1
- package/dist/tengo/lib/exec.delayed-compute-allocation.lib.tengo +43 -0
- package/dist/tengo/lib/exec.load-software.lib.tengo +32 -0
- package/dist/tengo/lib/exec.monetization.lib.tengo +7 -1
- package/dist/tengo/lib/exec.monetization_internal.lib.tengo +13 -19
- package/dist/tengo/lib/exec.runcmd.lib.tengo +350 -104
- package/dist/tengo/lib/feats.lib.tengo +1 -1
- package/dist/tengo/lib/feature-guard.lib.tengo +14 -0
- package/dist/tengo/lib/tpl.base.lib.tengo +3 -0
- package/dist/tengo/lib/waiter.lib.tengo +21 -6
- package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
- package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.delayed-compute-allocation.impl.plj.gz +0 -0
- package/dist/tengo/tpl/exec.exec-impl.plj.gz +0 -0
- package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
- package/dist/tengo/tpl/exec.load-software.impl.plj.gz +0 -0
- package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
- package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.venv-bin-path.plj.gz +0 -0
- package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
- package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
- package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
- package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
- package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
- package/package.json +2 -2
- package/dist/tengo/lib/exec.internal.lib.tengo +0 -430
|
@@ -14,6 +14,8 @@ constants := import("@platforma-sdk/workflow-tengo:exec.constants")
|
|
|
14
14
|
slices := import("@platforma-sdk/workflow-tengo:slices")
|
|
15
15
|
limits := import("@platforma-sdk/workflow-tengo:exec.limits")
|
|
16
16
|
|
|
17
|
+
delayedCompAlloc := import("@platforma-sdk/workflow-tengo:exec.delayed-compute-allocation")
|
|
18
|
+
|
|
17
19
|
_RTYPE_RUN_COMMAND_V1 := { Name: "RunCommand/executor", Version: "1" }
|
|
18
20
|
_RTYPE_RUN_COMMAND_EXEC_V2 := { Name: "RunCommand/executor", Version: "2" }
|
|
19
21
|
_RTYPE_RUN_COMMAND_BATCH_V2 := { Name: "RunCommand/batch", Version: "2" }
|
|
@@ -22,6 +24,42 @@ _RTYPE_RUN_COMMAND_ARGS := { Name: "RunCommandArgs", Version: "1" }
|
|
|
22
24
|
_RTYPE_RUN_COMMAND_OPTIONS := { Name: "run-command/options", Version: "1" }
|
|
23
25
|
_RTYPE_RUN_COMMAND_REFS := { Name: "RunCommandRefs", Version: "1" }
|
|
24
26
|
|
|
27
|
+
ARG_SCHEMA := {
|
|
28
|
+
"__options__,closed": true,
|
|
29
|
+
"type": "string,regex=string|expressionRef|variableRef",
|
|
30
|
+
"value": "string"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
RUN_CMD_PLAN_REFS_SCHEMA := "any"
|
|
34
|
+
|
|
35
|
+
RUN_CMD_PLAN_OPTIONS_SCHEMA := {
|
|
36
|
+
"cmd,?": ARG_SCHEMA,
|
|
37
|
+
"args": [ARG_SCHEMA],
|
|
38
|
+
"envs": { "any": ARG_SCHEMA },
|
|
39
|
+
"substRules": { "any": "string" },
|
|
40
|
+
"customPaths": [ARG_SCHEMA]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
RUN_CMD_PLAN_SCHEMA := {
|
|
44
|
+
"refs": RUN_CMD_PLAN_REFS_SCHEMA,
|
|
45
|
+
"options": RUN_CMD_PLAN_OPTIONS_SCHEMA
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_initStateFromPlan := func(state, initState, context) {
|
|
49
|
+
validation.assertType(initState, RUN_CMD_PLAN_SCHEMA, "invalid initial state for " + context)
|
|
50
|
+
|
|
51
|
+
initOptions := initState.options
|
|
52
|
+
state.options.cmd = maps.clone(initOptions.cmd)
|
|
53
|
+
state.options.args = maps.clone(initOptions.args)
|
|
54
|
+
state.options.envs = maps.clone(initOptions.envs)
|
|
55
|
+
state.options.substRules = maps.clone(initOptions.substRules)
|
|
56
|
+
state.options.customPaths = maps.clone(initOptions.customPaths)
|
|
57
|
+
|
|
58
|
+
for k, v in initState.refs {
|
|
59
|
+
state.refs[k] = v
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
25
63
|
|
|
26
64
|
_FIELD_ALLOCATION := "allocation" // not in v1
|
|
27
65
|
_FIELD_REFS := "refs"
|
|
@@ -38,7 +76,7 @@ _FIELD_WORKDIR_OUT := "workdirOut"
|
|
|
38
76
|
|
|
39
77
|
|
|
40
78
|
|
|
41
|
-
|
|
79
|
+
simpleArg := func(argument) {
|
|
42
80
|
return {
|
|
43
81
|
type: constants.ARG_TYPE_STRING,
|
|
44
82
|
value: argument
|
|
@@ -50,7 +88,7 @@ _createSimpleArg := func(argument) {
|
|
|
50
88
|
|
|
51
89
|
|
|
52
90
|
|
|
53
|
-
|
|
91
|
+
variableArg := func(argTpl) {
|
|
54
92
|
return {
|
|
55
93
|
type: constants.ARG_TYPE_VAR,
|
|
56
94
|
value: argTpl
|
|
@@ -64,58 +102,29 @@ _createVariableArg := func(argTpl) {
|
|
|
64
102
|
|
|
65
103
|
|
|
66
104
|
|
|
67
|
-
|
|
105
|
+
expressionArg := func(argTpl) {
|
|
68
106
|
return {
|
|
69
107
|
type: constants.ARG_TYPE_EXPRESSION,
|
|
70
108
|
value: argTpl
|
|
71
109
|
}
|
|
72
110
|
}
|
|
73
111
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
builder := func(workdir) {
|
|
112
|
+
_createAbstractRunCommandPlan := func(state, returnSelfFn) {
|
|
81
113
|
self := undefined
|
|
82
114
|
|
|
83
|
-
cmd := undefined
|
|
84
|
-
args := []
|
|
85
|
-
envs := {}
|
|
86
|
-
queue := ""
|
|
87
|
-
refs := {}
|
|
88
|
-
_allocation := undefined
|
|
89
|
-
|
|
90
|
-
substRules := {}
|
|
91
|
-
hasPatternArgs := false // TODO: deprecated, remove after a month of expressionRefs in prod.
|
|
92
|
-
hasExpressionArgs := false
|
|
93
|
-
customPaths := []
|
|
94
|
-
|
|
95
|
-
stdout := "stdout.txt"
|
|
96
|
-
stderr := "stderr.txt"
|
|
97
|
-
nErrorLines := 200
|
|
98
|
-
|
|
99
115
|
self = ll.toStrict({
|
|
100
116
|
|
|
101
117
|
|
|
102
118
|
|
|
103
119
|
|
|
104
120
|
|
|
105
|
-
allocation: func(allocation) {
|
|
106
|
-
validation.assertType(allocation, validation.reference, "runcmd.builder: allocation should be a valid reference")
|
|
107
|
-
_allocation = allocation
|
|
108
|
-
return self
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
121
|
cmd: func(commandName) {
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
if ll.isMap(commandName) {
|
|
123
|
+
self.cmdTyped(commandName.type, commandName.value)
|
|
124
|
+
} else {
|
|
125
|
+
state.options.cmd = simpleArg(commandName)
|
|
126
|
+
}
|
|
127
|
+
return returnSelfFn()
|
|
119
128
|
},
|
|
120
129
|
|
|
121
130
|
|
|
@@ -127,9 +136,8 @@ builder := func(workdir) {
|
|
|
127
136
|
|
|
128
137
|
|
|
129
138
|
cmdVar: func(commandTpl) {
|
|
130
|
-
cmd =
|
|
131
|
-
|
|
132
|
-
return self
|
|
139
|
+
state.options.cmd = variableArg(commandTpl)
|
|
140
|
+
return returnSelfFn()
|
|
133
141
|
},
|
|
134
142
|
|
|
135
143
|
|
|
@@ -141,14 +149,13 @@ builder := func(workdir) {
|
|
|
141
149
|
|
|
142
150
|
|
|
143
151
|
cmdExpression: func(commandTpl) {
|
|
144
|
-
cmd =
|
|
145
|
-
|
|
146
|
-
return self
|
|
152
|
+
state.options.cmd = expressionArg(commandTpl)
|
|
153
|
+
return returnSelfFn()
|
|
147
154
|
},
|
|
148
155
|
|
|
149
156
|
cmdTyped: func(type, value) {
|
|
150
157
|
ll.assert(slices.hasElement(constants.ARG_TYPES, type),
|
|
151
|
-
"runcmd.
|
|
158
|
+
"runcmd.plan.cmdTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
152
159
|
|
|
153
160
|
if type == constants.ARG_TYPE_STRING {
|
|
154
161
|
return self.cmd(value)
|
|
@@ -158,7 +165,7 @@ builder := func(workdir) {
|
|
|
158
165
|
return self.cmdVar(value)
|
|
159
166
|
}
|
|
160
167
|
|
|
161
|
-
ll.panic("runcmd.
|
|
168
|
+
ll.panic("runcmd.plan.cmdTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
162
169
|
},
|
|
163
170
|
|
|
164
171
|
|
|
@@ -167,8 +174,12 @@ builder := func(workdir) {
|
|
|
167
174
|
|
|
168
175
|
|
|
169
176
|
arg: func(arg) {
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
if ll.isMap(arg) {
|
|
178
|
+
self.argTyped(arg.type, arg.value)
|
|
179
|
+
} else {
|
|
180
|
+
state.options.args = append(state.options.args, simpleArg(arg))
|
|
181
|
+
}
|
|
182
|
+
return returnSelfFn()
|
|
172
183
|
},
|
|
173
184
|
|
|
174
185
|
|
|
@@ -180,9 +191,8 @@ builder := func(workdir) {
|
|
|
180
191
|
|
|
181
192
|
|
|
182
193
|
argVar: func(argTpl) {
|
|
183
|
-
args = append(args,
|
|
184
|
-
|
|
185
|
-
return self
|
|
194
|
+
state.options.args = append(state.options.args, variableArg(argTpl))
|
|
195
|
+
return returnSelfFn()
|
|
186
196
|
},
|
|
187
197
|
|
|
188
198
|
|
|
@@ -194,14 +204,13 @@ builder := func(workdir) {
|
|
|
194
204
|
|
|
195
205
|
|
|
196
206
|
argExpression: func(argTpl) {
|
|
197
|
-
args = append(args,
|
|
198
|
-
|
|
199
|
-
return self
|
|
207
|
+
state.options.args = append(state.options.args, expressionArg(argTpl))
|
|
208
|
+
return returnSelfFn()
|
|
200
209
|
},
|
|
201
210
|
|
|
202
211
|
argTyped: func(type, value) {
|
|
203
212
|
ll.assert(slices.hasElement(constants.ARG_TYPES, type),
|
|
204
|
-
"runcmd.
|
|
213
|
+
"runcmd.plan.argTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
205
214
|
|
|
206
215
|
if type == constants.ARG_TYPE_STRING {
|
|
207
216
|
return self.arg(value)
|
|
@@ -211,7 +220,15 @@ builder := func(workdir) {
|
|
|
211
220
|
return self.argVar(value)
|
|
212
221
|
}
|
|
213
222
|
|
|
214
|
-
ll.panic("runcmd.
|
|
223
|
+
ll.panic("runcmd.plan.argTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
resetArgs: func() {
|
|
230
|
+
state.options.args = []
|
|
231
|
+
return returnSelfFn()
|
|
215
232
|
},
|
|
216
233
|
|
|
217
234
|
|
|
@@ -222,13 +239,27 @@ builder := func(workdir) {
|
|
|
222
239
|
|
|
223
240
|
ref: func(refKey, ref) {
|
|
224
241
|
ll.assert(smart.isReference(ref),
|
|
225
|
-
"runcmd.
|
|
242
|
+
"runcmd.plan.ref() must be a reference (valid field or resource) %s", refKey)
|
|
226
243
|
|
|
227
|
-
ll.assert(!maps.containsKey(refs, refKey),
|
|
244
|
+
ll.assert(!maps.containsKey(state.refs, refKey),
|
|
228
245
|
"attempt to override existing reference %q", refKey)
|
|
229
246
|
|
|
230
|
-
refs[refKey] = ref
|
|
231
|
-
return
|
|
247
|
+
state.refs[refKey] = ref
|
|
248
|
+
return returnSelfFn()
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
refVar: func(varName, refKey, ref) {
|
|
260
|
+
self.ref(refKey, ref)
|
|
261
|
+
self.substitutionRule(varName, refKey)
|
|
262
|
+
return returnSelfFn()
|
|
232
263
|
},
|
|
233
264
|
|
|
234
265
|
|
|
@@ -238,8 +269,12 @@ builder := func(workdir) {
|
|
|
238
269
|
|
|
239
270
|
|
|
240
271
|
env: func(name, value) {
|
|
241
|
-
|
|
242
|
-
|
|
272
|
+
if ll.isMap(value) {
|
|
273
|
+
self.envTyped(name, value.type, value.value)
|
|
274
|
+
} else {
|
|
275
|
+
state.options.envs[name] = simpleArg(value)
|
|
276
|
+
}
|
|
277
|
+
return returnSelfFn()
|
|
243
278
|
},
|
|
244
279
|
|
|
245
280
|
|
|
@@ -250,9 +285,8 @@ builder := func(workdir) {
|
|
|
250
285
|
|
|
251
286
|
|
|
252
287
|
envVar: func(name, valueTpl) {
|
|
253
|
-
envs[name] =
|
|
254
|
-
|
|
255
|
-
return self
|
|
288
|
+
state.options.envs[name] = variableArg(valueTpl)
|
|
289
|
+
return returnSelfFn()
|
|
256
290
|
},
|
|
257
291
|
|
|
258
292
|
|
|
@@ -263,14 +297,13 @@ builder := func(workdir) {
|
|
|
263
297
|
|
|
264
298
|
|
|
265
299
|
envExpression: func(name, valueTpl) {
|
|
266
|
-
envs[name] =
|
|
267
|
-
|
|
268
|
-
return self
|
|
300
|
+
state.options.envs[name] = expressionArg(valueTpl)
|
|
301
|
+
return returnSelfFn()
|
|
269
302
|
},
|
|
270
303
|
|
|
271
304
|
envTyped: func(name, type, value) {
|
|
272
305
|
ll.assert(slices.hasElement(constants.ARG_TYPES, type),
|
|
273
|
-
"runcmd.
|
|
306
|
+
"runcmd.plan.envTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
274
307
|
|
|
275
308
|
if type == constants.ARG_TYPE_STRING {
|
|
276
309
|
return self.env(name, value)
|
|
@@ -280,7 +313,7 @@ builder := func(workdir) {
|
|
|
280
313
|
return self.envVar(name, value)
|
|
281
314
|
}
|
|
282
315
|
|
|
283
|
-
ll.panic("runcmd.
|
|
316
|
+
ll.panic("runcmd.plan.envTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
284
317
|
},
|
|
285
318
|
|
|
286
319
|
|
|
@@ -288,24 +321,50 @@ builder := func(workdir) {
|
|
|
288
321
|
|
|
289
322
|
|
|
290
323
|
|
|
324
|
+
addPath: func(path) {
|
|
325
|
+
if ll.isMap(path) {
|
|
326
|
+
self.addPathTyped(path.type, path.value)
|
|
327
|
+
} else {
|
|
328
|
+
state.options.customPaths = append(state.options.customPaths, simpleArg(path))
|
|
329
|
+
}
|
|
330
|
+
return returnSelfFn()
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
|
|
291
334
|
|
|
292
|
-
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
addPathVar: func(pathTpl) {
|
|
340
|
+
state.options.customPaths = append(state.options.customPaths, variableArg(pathTpl))
|
|
341
|
+
return returnSelfFn()
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
addPathExpression: func(pathTpl) {
|
|
351
|
+
state.options.customPaths = append(state.options.customPaths, expressionArg(pathTpl))
|
|
352
|
+
return returnSelfFn()
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
addPathTyped: func(type, value) {
|
|
293
356
|
ll.assert(slices.hasElement(constants.ARG_TYPES, type),
|
|
294
|
-
"runcmd.
|
|
357
|
+
"runcmd.plan.addPathTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
295
358
|
|
|
296
359
|
if type == constants.ARG_TYPE_STRING {
|
|
297
|
-
|
|
360
|
+
return self.addPath(value)
|
|
298
361
|
} else if type == constants.ARG_TYPE_EXPRESSION {
|
|
299
|
-
|
|
300
|
-
hasExpressionArgs = true
|
|
362
|
+
return self.addPathExpression(value)
|
|
301
363
|
} else if type == constants.ARG_TYPE_VAR {
|
|
302
|
-
|
|
303
|
-
hasPatternArgs = true
|
|
304
|
-
} else {
|
|
305
|
-
ll.panic("runcmd.builder().addToPath: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
364
|
+
return self.addPathVar(value)
|
|
306
365
|
}
|
|
307
366
|
|
|
308
|
-
|
|
367
|
+
ll.panic("runcmd.plan.addPathTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
|
|
309
368
|
},
|
|
310
369
|
|
|
311
370
|
|
|
@@ -316,8 +375,8 @@ builder := func(workdir) {
|
|
|
316
375
|
|
|
317
376
|
|
|
318
377
|
substitutionRule: func(varName, refKey) {
|
|
319
|
-
substRules[varName] = refKey
|
|
320
|
-
return
|
|
378
|
+
state.options.substRules[varName] = refKey
|
|
379
|
+
return returnSelfFn()
|
|
321
380
|
},
|
|
322
381
|
|
|
323
382
|
|
|
@@ -327,8 +386,116 @@ builder := func(workdir) {
|
|
|
327
386
|
|
|
328
387
|
substitutionRules: func(rules) {
|
|
329
388
|
for k, v in rules {
|
|
330
|
-
substRules[k] = v
|
|
389
|
+
state.options.substRules[k] = v
|
|
390
|
+
}
|
|
391
|
+
return returnSelfFn()
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
return self
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
createRunCommandPlan := func(...initialState) {
|
|
399
|
+
state := {
|
|
400
|
+
refs: {},
|
|
401
|
+
options: {
|
|
402
|
+
cmd: undefined,
|
|
403
|
+
args: [],
|
|
404
|
+
envs: {},
|
|
405
|
+
substRules: {},
|
|
406
|
+
customPaths: []
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if len(initialState) == 1 {
|
|
411
|
+
initState := initialState[0]
|
|
412
|
+
_initStateFromPlan(state, initState, "run command plan")
|
|
413
|
+
} else {
|
|
414
|
+
ll.assert(len(initialState) == 0, "createRunCommandPlan accepts at most one argument")
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
self := undefined
|
|
418
|
+
|
|
419
|
+
self = oop.inherit(_createAbstractRunCommandPlan(state, func() { return self }), {
|
|
420
|
+
state: func() {
|
|
421
|
+
newState := {
|
|
422
|
+
options: maps.clone(state.options),
|
|
423
|
+
refs: {}
|
|
331
424
|
}
|
|
425
|
+
for k, v in state.refs {
|
|
426
|
+
newState.refs[k] = v
|
|
427
|
+
}
|
|
428
|
+
return newState
|
|
429
|
+
}
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
return self
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
builder := func(workdir, ...initialState) {
|
|
442
|
+
self := undefined
|
|
443
|
+
|
|
444
|
+
state := {
|
|
445
|
+
refs: {},
|
|
446
|
+
options: {
|
|
447
|
+
cmd: undefined,
|
|
448
|
+
args: [],
|
|
449
|
+
envs: {},
|
|
450
|
+
substRules: {},
|
|
451
|
+
customPaths: []
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if len(initialState) == 1 {
|
|
456
|
+
initState := initialState[0]
|
|
457
|
+
_initStateFromPlan(state, initState, "run command builder")
|
|
458
|
+
} else {
|
|
459
|
+
ll.assert(len(initialState) == 0, "builder accepts at most two arguments")
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
allocation := undefined
|
|
463
|
+
queue := undefined
|
|
464
|
+
cpu := undefined
|
|
465
|
+
ram := undefined
|
|
466
|
+
|
|
467
|
+
stdout := "stdout.txt"
|
|
468
|
+
stderr := "stderr.txt"
|
|
469
|
+
nErrorLines := 200
|
|
470
|
+
|
|
471
|
+
self = oop.inherit(_createAbstractRunCommandPlan(state, func() { return self }), {
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
allocation: func(value) {
|
|
478
|
+
validation.assertType(value, validation.reference, "runcmd.builder: allocation should be a valid reference")
|
|
479
|
+
allocation = value
|
|
480
|
+
return self
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
request: func(request) {
|
|
489
|
+
validation.assertType(request, {
|
|
490
|
+
"queue": "string",
|
|
491
|
+
"cpu,?": "number",
|
|
492
|
+
"ram,?": ["or", "number", "string"]
|
|
493
|
+
}, "runcmd.builder.request: request must be a valid request")
|
|
494
|
+
|
|
495
|
+
queue = request.queue
|
|
496
|
+
cpu = request.cpu
|
|
497
|
+
ram = request.ram
|
|
498
|
+
|
|
332
499
|
return self
|
|
333
500
|
},
|
|
334
501
|
|
|
@@ -347,6 +514,29 @@ builder := func(workdir) {
|
|
|
347
514
|
|
|
348
515
|
|
|
349
516
|
|
|
517
|
+
mem: func(value) {
|
|
518
|
+
validation.assertType(value, ["or", "number", "string"], "exec.builder.mem: RAM amount should be a number or string")
|
|
519
|
+
ll.assert(is_string(value) || value > 0, "exec.builder.mem: amount in bytes should be greater than 0")
|
|
520
|
+
ram = value
|
|
521
|
+
return self
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
cpu: func(value) {
|
|
530
|
+
validation.assertType(value, "number", "runcmd.builder.cpu: value must be a number")
|
|
531
|
+
cpu = value
|
|
532
|
+
return self
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
350
540
|
stdout: func(fileName) {
|
|
351
541
|
stdout = fileName
|
|
352
542
|
return self
|
|
@@ -379,6 +569,45 @@ builder := func(workdir) {
|
|
|
379
569
|
|
|
380
570
|
build: func() {
|
|
381
571
|
runRes := undefined
|
|
572
|
+
options := state.options
|
|
573
|
+
refs := state.refs
|
|
574
|
+
|
|
575
|
+
hasPatternArgs := false
|
|
576
|
+
hasExpressionArgs := false
|
|
577
|
+
|
|
578
|
+
check := func(arg) {
|
|
579
|
+
if !ll.isMap(arg) {
|
|
580
|
+
return
|
|
581
|
+
}
|
|
582
|
+
if arg.type == constants.ARG_TYPE_VAR {
|
|
583
|
+
hasPatternArgs = true
|
|
584
|
+
}
|
|
585
|
+
if arg.type == constants.ARG_TYPE_EXPRESSION {
|
|
586
|
+
hasExpressionArgs = true
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
check(options.cmd)
|
|
591
|
+
|
|
592
|
+
for arg in options.args {
|
|
593
|
+
check(arg)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
for _, env in options.envs {
|
|
597
|
+
check(env)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
for path in options.customPaths {
|
|
601
|
+
check(path)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
ll.assert(is_undefined(allocation) || (is_undefined(cpu) && is_undefined(ram)),
|
|
608
|
+
"runcmd.builder.build: allocation cannot be set along with cpu or ram")
|
|
609
|
+
|
|
610
|
+
ll.assert(!is_undefined(queue), "queue must be set")
|
|
382
611
|
|
|
383
612
|
useBatch := limits.useBatch(queue)
|
|
384
613
|
|
|
@@ -399,51 +628,60 @@ builder := func(workdir) {
|
|
|
399
628
|
|
|
400
629
|
|
|
401
630
|
|
|
402
|
-
ll.assert(!hasPatternArgs || len(substRules) != 0,
|
|
631
|
+
ll.assert(!hasPatternArgs || len(options.substRules) != 0,
|
|
403
632
|
"found pattern argument, but no substitution rules were set: hasPatternArgs: %v, substRules: %v, cmd: %v, args: %v, envs: %v",
|
|
404
|
-
hasPatternArgs, substRules, cmd, args, envs)
|
|
633
|
+
hasPatternArgs, options.substRules, options.cmd, options.args, options.envs)
|
|
405
634
|
ll.assert(!hasExpressionArgs || feats.commandExpressions,
|
|
406
635
|
"runcmd.builder().build: expression arguments must be enabled only if platforma backend supports expressions, found: %v",
|
|
407
636
|
hasExpressionArgs)
|
|
408
637
|
|
|
409
|
-
if
|
|
410
|
-
|
|
638
|
+
if !is_undefined(allocation) {
|
|
639
|
+
runRes.getField(_FIELD_ALLOCATION).set(allocation)
|
|
640
|
+
} else {
|
|
641
|
+
request := {
|
|
642
|
+
queue: queue
|
|
643
|
+
}
|
|
644
|
+
if !is_undefined(cpu) {
|
|
645
|
+
request.cpu = cpu
|
|
646
|
+
}
|
|
647
|
+
if !is_undefined(ram) {
|
|
648
|
+
request.ram = ram
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
411
653
|
|
|
412
654
|
|
|
413
|
-
_quotaRef := limits.quotaBuilder().queue(queue).build()
|
|
414
|
-
_resReqRef := limits.computeRequestBuilder().queue(queue).quota(_quotaRef).build()
|
|
415
|
-
_allocation = _resReqRef.allocation
|
|
416
|
-
}
|
|
417
655
|
|
|
418
|
-
runRes.getField(_FIELD_ALLOCATION).set(
|
|
656
|
+
runRes.getField(_FIELD_ALLOCATION).set(delayedCompAlloc.create(workdir, request))
|
|
419
657
|
}
|
|
420
658
|
|
|
421
659
|
refsRes := smart.createMapResourceWithType(_RTYPE_RUN_COMMAND_REFS, refs)
|
|
422
660
|
runRes.getField(_FIELD_REFS).set(refsRes)
|
|
423
661
|
|
|
424
|
-
cmdRes := smart.createValueResource(_RTYPE_RUN_COMMAND_CMD, json.encode(cmd))
|
|
662
|
+
cmdRes := smart.createValueResource(_RTYPE_RUN_COMMAND_CMD, json.encode(options.cmd))
|
|
425
663
|
runRes.getField(_FIELD_CMD).set(cmdRes)
|
|
426
664
|
|
|
427
|
-
|
|
665
|
+
buildOptions := {
|
|
428
666
|
queueName: queue,
|
|
429
667
|
errorLines: nErrorLines,
|
|
430
668
|
redirectStdout: stdout,
|
|
431
669
|
redirectStderr: stderr,
|
|
432
|
-
env: envs,
|
|
433
|
-
additionalPaths: customPaths,
|
|
434
|
-
substitutions: substRules
|
|
670
|
+
env: options.envs,
|
|
671
|
+
additionalPaths: options.customPaths,
|
|
672
|
+
substitutions: options.substRules
|
|
435
673
|
}
|
|
436
674
|
|
|
437
|
-
optionsRes := smart.createValueResource(_RTYPE_RUN_COMMAND_OPTIONS, json.encode(
|
|
675
|
+
optionsRes := smart.createValueResource(_RTYPE_RUN_COMMAND_OPTIONS, json.encode(buildOptions))
|
|
438
676
|
runRes.getField(_FIELD_OPTIONS).set(optionsRes)
|
|
439
677
|
|
|
440
|
-
argsRes := smart.createValueResource(_RTYPE_RUN_COMMAND_ARGS, json.encode(args))
|
|
678
|
+
argsRes := smart.createValueResource(_RTYPE_RUN_COMMAND_ARGS, json.encode(options.args))
|
|
441
679
|
runRes.getField(_FIELD_ARGS).set(argsRes)
|
|
442
680
|
|
|
443
|
-
res :=
|
|
681
|
+
res := oop.inherit(runRes.lockAndBuild(), {
|
|
444
682
|
"workdir": runRes.outputs()[_FIELD_WORKDIR_OUT],
|
|
445
|
-
"options":
|
|
446
|
-
})
|
|
683
|
+
"options": buildOptions
|
|
684
|
+
})
|
|
447
685
|
|
|
448
686
|
return res
|
|
449
687
|
}
|
|
@@ -453,5 +691,13 @@ builder := func(workdir) {
|
|
|
453
691
|
}
|
|
454
692
|
|
|
455
693
|
export ll.toStrict({
|
|
456
|
-
builder: builder
|
|
694
|
+
builder: builder,
|
|
695
|
+
simpleArg: simpleArg,
|
|
696
|
+
variableArg: variableArg,
|
|
697
|
+
expressionArg: expressionArg,
|
|
698
|
+
createRunCommandPlan: createRunCommandPlan,
|
|
699
|
+
ARG_SCHEMA: ARG_SCHEMA,
|
|
700
|
+
RUN_CMD_PLAN_REFS_SCHEMA: RUN_CMD_PLAN_REFS_SCHEMA,
|
|
701
|
+
RUN_CMD_PLAN_OPTIONS_SCHEMA: RUN_CMD_PLAN_OPTIONS_SCHEMA,
|
|
702
|
+
RUN_CMD_PLAN_SCHEMA: RUN_CMD_PLAN_SCHEMA
|
|
457
703
|
})
|
|
@@ -32,7 +32,7 @@ _hasRunner := func(e_id) {
|
|
|
32
32
|
|
|
33
33
|
export ll.toStrict({
|
|
34
34
|
hasExec: _hasRunner("executor"), // local binary execution is available
|
|
35
|
-
hasBatch: _hasRunner("batch"),
|
|
35
|
+
hasBatch: _hasRunner("batch"), // batch system execution is available
|
|
36
36
|
|
|
37
37
|
pureFutureFields: _isEnabled("pureFutureFields") || _api >= 1, // 'pure' future fields magic that provides deduplication
|
|
38
38
|
commandExpressions: _isEnabled("commandExpressions") || _api >= 2, // rich expressions in command arguments ( {{ system.ram_bytes / 20 }} )
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
7
|
+
feat := import("@platforma-sdk/workflow-tengo:feats")
|
|
8
|
+
|
|
9
|
+
if(!feat.commandExpressions) {
|
|
10
|
+
ll.panic("INCOMPATIBLE PLATFORMA BACKEND, PLEASE UPGRADE PLATFORMA TO THE LATEST VERSION! " +
|
|
11
|
+
"(commandExpressions feature is not supported)")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {}
|