@platforma-sdk/workflow-tengo 4.8.1 → 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.
Files changed (47) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +6 -4
  3. package/dist/index.mjs +6 -4
  4. package/dist/tengo/lib/exec.R.internal.lib.tengo +4 -1
  5. package/dist/tengo/lib/exec.delayed-compute-allocation.lib.tengo +43 -0
  6. package/dist/tengo/lib/exec.load-software.lib.tengo +32 -0
  7. package/dist/tengo/lib/exec.monetization.lib.tengo +7 -1
  8. package/dist/tengo/lib/exec.monetization_internal.lib.tengo +13 -19
  9. package/dist/tengo/lib/exec.runcmd.lib.tengo +350 -104
  10. package/dist/tengo/lib/feats.lib.tengo +1 -1
  11. package/dist/tengo/lib/feature-guard.lib.tengo +14 -0
  12. package/dist/tengo/lib/tpl.base.lib.tengo +3 -0
  13. package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
  14. package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
  15. package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
  16. package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
  17. package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
  18. package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
  19. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  20. package/dist/tengo/tpl/exec.delayed-compute-allocation.impl.plj.gz +0 -0
  21. package/dist/tengo/tpl/exec.exec-impl.plj.gz +0 -0
  22. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  23. package/dist/tengo/tpl/exec.load-software.impl.plj.gz +0 -0
  24. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  25. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  26. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  27. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  28. package/dist/tengo/tpl/exec.python.venv-bin-path.plj.gz +0 -0
  29. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  30. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  31. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  32. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  33. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  34. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  35. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  36. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  37. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  38. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  39. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  40. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  41. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  42. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  43. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  44. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  45. package/package.json +1 -1
  46. package/dist/tengo/lib/exec.internal.lib.tengo +0 -430
  47. package/dist/tengo/tpl/exec.delayed_compute_allocation.plj.gz +0 -0
@@ -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
- _createSimpleArg := func(argument) {
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
- _createVariableArg := func(argTpl) {
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
- _createExpressionArg := func(argTpl) {
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
- cmd = _createSimpleArg(commandName)
118
- return self
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 = _createVariableArg(commandTpl)
131
- hasPatternArgs = true
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 = _createExpressionArg(commandTpl)
145
- hasExpressionArgs = true
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.builder().cmdTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
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.builder().cmdTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
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
- args = append(args, _createSimpleArg(arg))
171
- return self
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, _createVariableArg(argTpl))
184
- hasPatternArgs = true
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, _createExpressionArg(argTpl))
198
- hasExpressionArgs = true
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.builder().argTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
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.builder().argTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
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.builder().ref() must be a reference (valid field or resource) %s", refKey)
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 self
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
- envs[name] = value
242
- return self
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] = _createVariableArg(valueTpl)
254
- hasPatternArgs = true
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] = _createExpressionArg(valueTpl)
267
- hasExpressionArgs = true
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.builder().envTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
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.builder().envTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
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
- addToPath: func(type, value) {
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.builder().addToPath: unknown type %s, expect: %v", type, constants.ARG_TYPES)
357
+ "runcmd.plan.addPathTyped: unknown type %s, expect: %v", type, constants.ARG_TYPES)
295
358
 
296
359
  if type == constants.ARG_TYPE_STRING {
297
- customPaths = append(customPaths, _createSimpleArg(value))
360
+ return self.addPath(value)
298
361
  } else if type == constants.ARG_TYPE_EXPRESSION {
299
- customPaths = append(customPaths, _createExpressionArg(value))
300
- hasExpressionArgs = true
362
+ return self.addPathExpression(value)
301
363
  } else if type == constants.ARG_TYPE_VAR {
302
- customPaths = append(customPaths, _createVariableArg(value))
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
- return self
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 self
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 feats.computeLimits || useBatch {
410
- if !smart.isReference(_allocation) {
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(_allocation)
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
- options := {
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(options))
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 := ll.toStrict(oop.inherit(runRes.lockAndBuild(), {
681
+ res := oop.inherit(runRes.lockAndBuild(), {
444
682
  "workdir": runRes.outputs()[_FIELD_WORKDIR_OUT],
445
- "options": 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"), // batch system execution is available
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 {}