@platforma-sdk/workflow-tengo 6.8.3 → 6.10.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/tengo/lib/exec.constants.lib.tengo +2 -0
- package/dist/tengo/lib/exec.delayed-compute-allocation.lib.tengo +5 -1
- package/dist/tengo/lib/exec.formula.lib.tengo +13 -1
- package/dist/tengo/lib/exec.lib.tengo +152 -5
- package/dist/tengo/lib/exec.limits.lib.tengo +31 -0
- package/dist/tengo/lib/exec.tmpdir-compat.lib.tengo +270 -0
- package/dist/tengo/lib/feats.lib.tengo +12 -0
- package/dist/tengo/tpl/annotations.compute.plj.gz +0 -0
- package/dist/tengo/tpl/anonymize.deanonymize.plj.gz +0 -0
- package/dist/tengo/tpl/anonymize.impl.plj.gz +0 -0
- 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/check_network.workdir_type_name_extractor.plj.gz +0 -0
- package/dist/tengo/tpl/exec.conda.create-env.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.build-table.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-parquet-pcolumn-chunk.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.merge-resource-maps.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.parse-to-json.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.process-pcolumn-batch-split.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.process-pcolumn-batch.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/pt.import-dir.plj.gz +0 -0
- package/dist/tengo/tpl/pt.workflow-run.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/dist/tengo/tpl/workflow.query-context-filter.plj.gz +0 -0
- package/package.json +2 -2
|
@@ -28,6 +28,7 @@ RUNNER_EXECUTOR := "executor" // local binary execution
|
|
|
28
28
|
META_INPUT_MEM_FORMULA := "__memFormula__"
|
|
29
29
|
META_INPUT_CPU_FORMULA := "__cpuFormula__"
|
|
30
30
|
META_INPUT_GPU_FORMULA := "__gpuFormula__"
|
|
31
|
+
META_INPUT_SCRATCH_FORMULA := "__scratchFormula__"
|
|
31
32
|
REGULAR_INPUT_LINE_COUNT := "__metric_lineCount__"
|
|
32
33
|
|
|
33
34
|
export ll.toStrict({
|
|
@@ -49,5 +50,6 @@ export ll.toStrict({
|
|
|
49
50
|
META_INPUT_MEM_FORMULA: META_INPUT_MEM_FORMULA,
|
|
50
51
|
META_INPUT_CPU_FORMULA: META_INPUT_CPU_FORMULA,
|
|
51
52
|
META_INPUT_GPU_FORMULA: META_INPUT_GPU_FORMULA,
|
|
53
|
+
META_INPUT_SCRATCH_FORMULA: META_INPUT_SCRATCH_FORMULA,
|
|
52
54
|
REGULAR_INPUT_LINE_COUNT: REGULAR_INPUT_LINE_COUNT
|
|
53
55
|
})
|
|
@@ -22,7 +22,8 @@ create := func(workdir, req) {
|
|
|
22
22
|
"queue": "string",
|
|
23
23
|
"cpu,?": "number",
|
|
24
24
|
"ram,?": ["or", "number", "string"],
|
|
25
|
-
"gpuMemory,?": "string"
|
|
25
|
+
"gpuMemory,?": "string",
|
|
26
|
+
"scratchFreeSpace,?": ["or", "number", "string"]
|
|
26
27
|
}, "request must be a valid request")
|
|
27
28
|
|
|
28
29
|
reqMap := { queue: req.queue }
|
|
@@ -35,6 +36,9 @@ create := func(workdir, req) {
|
|
|
35
36
|
if !is_undefined(req.gpuMemory) {
|
|
36
37
|
reqMap.gpuMemory = req.gpuMemory
|
|
37
38
|
}
|
|
39
|
+
if !is_undefined(req.scratchFreeSpace) {
|
|
40
|
+
reqMap.scratchFreeSpace = req.scratchFreeSpace
|
|
41
|
+
}
|
|
38
42
|
|
|
39
43
|
delayedComputeAllocation := render.createEphemeral(tpl, {
|
|
40
44
|
request: smart.createJsonResource(reqMap),
|
|
@@ -298,12 +298,21 @@ referencedMetricFiles := func(resolvedNode) {
|
|
|
298
298
|
|
|
299
299
|
|
|
300
300
|
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
301
309
|
|
|
302
310
|
|
|
303
311
|
|
|
304
312
|
applyFormulaFallback := func(dims) {
|
|
305
313
|
gpu := is_undefined(dims.gpu) ? {} : dims.gpu
|
|
306
|
-
|
|
314
|
+
scratch := is_undefined(dims.scratch) ? {} : dims.scratch
|
|
315
|
+
res := { ram: dims.ram.static, cpu: dims.cpu.static, gpu: gpu.static, scratch: scratch.static, err: undefined }
|
|
307
316
|
if !is_undefined(_unwrap(dims.ram.ast)) && is_undefined(res.ram) {
|
|
308
317
|
if is_undefined(dims.ram.fallback) {
|
|
309
318
|
res.err = "exec.builder: the RAM formula needs a static fallback on backends that can't evaluate resource formulas at run time. Provide .staticFallback(...) on the RAM formula, set a static ram, or upgrade the backend."
|
|
@@ -325,6 +334,9 @@ applyFormulaFallback := func(dims) {
|
|
|
325
334
|
}
|
|
326
335
|
res.gpu = gpu.fallback
|
|
327
336
|
}
|
|
337
|
+
if !is_undefined(_unwrap(scratch.ast)) && is_undefined(res.scratch) {
|
|
338
|
+
res.scratch = scratch.fallback
|
|
339
|
+
}
|
|
328
340
|
return res
|
|
329
341
|
}
|
|
330
342
|
|
|
@@ -19,6 +19,7 @@ constants := import("@platforma-sdk/workflow-tengo:constants")
|
|
|
19
19
|
canonical := import("@platforma-sdk/workflow-tengo:canonical")
|
|
20
20
|
monetization := import("@platforma-sdk/workflow-tengo:exec.monetization_internal")
|
|
21
21
|
execConstants := import("@platforma-sdk/workflow-tengo:exec.constants")
|
|
22
|
+
tmpdirCompat := import("@platforma-sdk/workflow-tengo:exec.tmpdir-compat")
|
|
22
23
|
execFormula := import("@platforma-sdk/workflow-tengo:exec.formula")
|
|
23
24
|
units := import("@platforma-sdk/workflow-tengo:units")
|
|
24
25
|
feats := import("@platforma-sdk/workflow-tengo:feats")
|
|
@@ -65,6 +66,16 @@ _assertValidGpuRequest := func(amount, ctx) {
|
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
|
|
69
|
+
_assertValidScratchRequest := func(amount, ctx) {
|
|
70
|
+
validation.assertType(amount, ["or", "number", "string"], ctx + ": scratch space amount must be a number of bytes or a size string like '500GiB'")
|
|
71
|
+
ll.assert(is_string(amount) || amount == 0 || amount >= 16 * units.MiB, ctx + ": scratch space in bytes should be at least 16MiB, or exactly 0 to ask only for a temporary directory (did you pass bytes instead of GiB?)")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
68
79
|
builder := func() {
|
|
69
80
|
self := undefined
|
|
70
81
|
|
|
@@ -92,6 +103,7 @@ builder := func() {
|
|
|
92
103
|
cpuRequest := undefined
|
|
93
104
|
ramRequest := undefined
|
|
94
105
|
gpuMemory := undefined
|
|
106
|
+
scratchFreeSpace := undefined
|
|
95
107
|
|
|
96
108
|
|
|
97
109
|
|
|
@@ -103,6 +115,8 @@ builder := func() {
|
|
|
103
115
|
cpuFormulaFallback := undefined
|
|
104
116
|
gpuFormulaAst := undefined
|
|
105
117
|
gpuFormulaFallback := undefined
|
|
118
|
+
scratchFormulaAst := undefined
|
|
119
|
+
scratchFormulaFallback := undefined
|
|
106
120
|
fileTags := {} // fileName -> tag (for f.size("tag") / f.lineCount("tag") aggregation)
|
|
107
121
|
|
|
108
122
|
commandName := ""
|
|
@@ -520,6 +534,27 @@ builder := func() {
|
|
|
520
534
|
|
|
521
535
|
|
|
522
536
|
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
523
558
|
|
|
524
559
|
|
|
525
560
|
|
|
@@ -592,6 +627,20 @@ builder := func() {
|
|
|
592
627
|
memFormulaFallback = undefined
|
|
593
628
|
}
|
|
594
629
|
}
|
|
630
|
+
setScratch := func(v, ctx) {
|
|
631
|
+
if execFormula.isFormula(v) {
|
|
632
|
+
scratchFormulaAst = execFormula.astOf(v)
|
|
633
|
+
scratchFormulaFallback = undefined
|
|
634
|
+
fb := execFormula.fallbackOf(v)
|
|
635
|
+
if !is_undefined(fb) { _assertValidScratchRequest(fb, ctx + " scratchFreeSpace fallback"); scratchFormulaFallback = fb }
|
|
636
|
+
scratchFreeSpace = undefined
|
|
637
|
+
} else {
|
|
638
|
+
_assertValidScratchRequest(v, ctx + " scratchFreeSpace")
|
|
639
|
+
scratchFreeSpace = v
|
|
640
|
+
scratchFormulaAst = undefined
|
|
641
|
+
scratchFormulaFallback = undefined
|
|
642
|
+
}
|
|
643
|
+
}
|
|
595
644
|
setVram := func(v, ctx) {
|
|
596
645
|
if execFormula.isFormula(v) {
|
|
597
646
|
gpuFormulaAst = execFormula.astOf(v)
|
|
@@ -610,8 +659,8 @@ builder := func() {
|
|
|
610
659
|
assertKeys := func(block, name, allowVram) {
|
|
611
660
|
ll.assert(ll.isMap(block), "exec.builder.resources.%s: expected a map", name)
|
|
612
661
|
for k, _ in block {
|
|
613
|
-
ok := k == "cpu" || k == "ram" || (allowVram && k == "vram")
|
|
614
|
-
ll.assert(ok, "exec.builder.resources.%s: unknown key %q (allowed: %s)", name, k, allowVram ? "cpu, ram, vram" : "cpu, ram")
|
|
662
|
+
ok := k == "cpu" || k == "ram" || k == "scratchFreeSpace" || (allowVram && k == "vram")
|
|
663
|
+
ll.assert(ok, "exec.builder.resources.%s: unknown key %q (allowed: %s)", name, k, allowVram ? "cpu, ram, vram, scratchFreeSpace" : "cpu, ram, scratchFreeSpace")
|
|
615
664
|
}
|
|
616
665
|
ll.assert(!is_undefined(block.cpu) && !is_undefined(block.ram),
|
|
617
666
|
"exec.builder.resources.%s: cpu and ram are required", name)
|
|
@@ -636,15 +685,30 @@ builder := func() {
|
|
|
636
685
|
"exec.builder.resources: onGPU was set without onCPU (GPU required), but this backend has no GPU support (exec.hasGpu is false). Add an onCPU block for an adaptive CPU fallback, or run on a GPU-enabled backend.")
|
|
637
686
|
}
|
|
638
687
|
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
setScratchFrom := func(block, ctx) {
|
|
692
|
+
if is_undefined(block.scratchFreeSpace) {
|
|
693
|
+
scratchFreeSpace = undefined
|
|
694
|
+
scratchFormulaAst = undefined
|
|
695
|
+
scratchFormulaFallback = undefined
|
|
696
|
+
return
|
|
697
|
+
}
|
|
698
|
+
setScratch(block.scratchFreeSpace, ctx)
|
|
699
|
+
}
|
|
700
|
+
|
|
639
701
|
if useGPU {
|
|
640
702
|
g := spec.onGPU
|
|
641
703
|
setCpu(g.cpu, "resources.onGPU")
|
|
642
704
|
setRam(g.ram, "resources.onGPU")
|
|
643
705
|
setVram(g.vram, "resources.onGPU")
|
|
706
|
+
setScratchFrom(g, "resources.onGPU")
|
|
644
707
|
} else {
|
|
645
708
|
c := spec.onCPU
|
|
646
709
|
setCpu(c.cpu, "resources.onCPU")
|
|
647
710
|
setRam(c.ram, "resources.onCPU")
|
|
711
|
+
setScratchFrom(c, "resources.onCPU")
|
|
648
712
|
|
|
649
713
|
|
|
650
714
|
gpuMemory = undefined
|
|
@@ -1277,6 +1341,53 @@ builder := func() {
|
|
|
1277
1341
|
|
|
1278
1342
|
|
|
1279
1343
|
|
|
1344
|
+
|
|
1345
|
+
|
|
1346
|
+
|
|
1347
|
+
tmpdirCompatNeeded := tmpdirCompat.isNeeded(
|
|
1348
|
+
feats,
|
|
1349
|
+
tmpdirCompat.isSizedRequest(scratchFreeSpace, scratchFormulaAst)
|
|
1350
|
+
)
|
|
1351
|
+
if tmpdirCompatNeeded {
|
|
1352
|
+
filesToWrite[tmpdirCompat.SCRIPT_FILE_NAME] = tmpdirCompat.script()
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
args = slices.map(args, tmpdirCompat.rewriteScratchExpressions)
|
|
1360
|
+
argsTyped = slices.map(argsTyped, func(a) {
|
|
1361
|
+
a.value = tmpdirCompat.rewriteScratchExpressions(a.value)
|
|
1362
|
+
return a
|
|
1363
|
+
})
|
|
1364
|
+
envs = maps.mapValues(envs, tmpdirCompat.rewriteScratchExpressions)
|
|
1365
|
+
envsTyped = maps.mapValues(envsTyped, func(e) {
|
|
1366
|
+
e.value = tmpdirCompat.rewriteScratchExpressions(e.value)
|
|
1367
|
+
return e
|
|
1368
|
+
})
|
|
1369
|
+
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
if is_undefined(soft) {
|
|
1373
|
+
wrapped := tmpdirCompat.wrapCommand(cmd)
|
|
1374
|
+
cmd = wrapped.cmd
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
|
|
1378
|
+
|
|
1379
|
+
args = tmpdirCompat.concat(wrapped.prependArgs, args)
|
|
1380
|
+
argsTyped = tmpdirCompat.concat(
|
|
1381
|
+
slices.map(wrapped.prependArgs, func(a) {
|
|
1382
|
+
return { type: execConstants.ARG_TYPE_STRING, value: a }
|
|
1383
|
+
}),
|
|
1384
|
+
argsTyped)
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
|
|
1280
1391
|
filesToWriteRefs := maps.mapValues(filesToWrite, func(v) {
|
|
1281
1392
|
if smart.isReference(v) { return v }
|
|
1282
1393
|
return smart.createValueResource(constants.RTYPE_BINARY_VALUE, v)
|
|
@@ -1333,10 +1444,12 @@ builder := func() {
|
|
|
1333
1444
|
|
|
1334
1445
|
|
|
1335
1446
|
|
|
1336
|
-
hasFormula := !is_undefined(memFormulaAst) || !is_undefined(cpuFormulaAst) ||
|
|
1447
|
+
hasFormula := !is_undefined(memFormulaAst) || !is_undefined(cpuFormulaAst) ||
|
|
1448
|
+
!is_undefined(gpuFormulaAst) || !is_undefined(scratchFormulaAst)
|
|
1337
1449
|
resolvedMem := undefined
|
|
1338
1450
|
resolvedCpu := undefined
|
|
1339
1451
|
resolvedGpu := undefined
|
|
1452
|
+
resolvedScratch := undefined
|
|
1340
1453
|
lineCountMapResource := undefined
|
|
1341
1454
|
|
|
1342
1455
|
if hasFormula {
|
|
@@ -1358,14 +1471,20 @@ builder := func() {
|
|
|
1358
1471
|
fb := execFormula.applyFormulaFallback({
|
|
1359
1472
|
ram: { ast: memFormulaAst, fallback: memFormulaFallback, static: ramRequest },
|
|
1360
1473
|
cpu: { ast: cpuFormulaAst, fallback: cpuFormulaFallback, static: cpuRequest },
|
|
1361
|
-
gpu: { ast: gpuFormulaAst, fallback: gpuFormulaFallback, static: gpuMemory }
|
|
1474
|
+
gpu: { ast: gpuFormulaAst, fallback: gpuFormulaFallback, static: gpuMemory },
|
|
1475
|
+
scratch: { ast: scratchFormulaAst, fallback: scratchFormulaFallback, static: scratchFreeSpace }
|
|
1362
1476
|
})
|
|
1363
1477
|
ll.assert(is_undefined(fb.err), fb.err)
|
|
1364
1478
|
ramRequest = fb.ram
|
|
1365
1479
|
cpuRequest = fb.cpu
|
|
1366
1480
|
gpuMemory = fb.gpu
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
|
|
1484
|
+
scratchFreeSpace = fb.scratch
|
|
1367
1485
|
if is_int(ramRequest) { ramRequest = string(ramRequest) + "b" }
|
|
1368
1486
|
if is_int(gpuMemory) { gpuMemory = string(gpuMemory) + "b" }
|
|
1487
|
+
if is_int(scratchFreeSpace) { scratchFreeSpace = string(scratchFreeSpace) + "b" }
|
|
1369
1488
|
} else {
|
|
1370
1489
|
tagMap := {}
|
|
1371
1490
|
for fileName, tag in fileTags {
|
|
@@ -1390,6 +1509,11 @@ builder := func() {
|
|
|
1390
1509
|
refs := execFormula.referencedMetricFiles(resolvedGpu)
|
|
1391
1510
|
if !is_undefined(refs.lineCount) { sets.add(neededLineCount, refs.lineCount...) }
|
|
1392
1511
|
}
|
|
1512
|
+
if !is_undefined(scratchFormulaAst) {
|
|
1513
|
+
resolvedScratch = execFormula.resolveAst(scratchFormulaAst, tagMap, allFiles)
|
|
1514
|
+
refs := execFormula.referencedMetricFiles(resolvedScratch)
|
|
1515
|
+
if !is_undefined(refs.lineCount) { sets.add(neededLineCount, refs.lineCount...) }
|
|
1516
|
+
}
|
|
1393
1517
|
|
|
1394
1518
|
if len(neededLineCount) > 0 {
|
|
1395
1519
|
perFile := {}
|
|
@@ -1419,6 +1543,24 @@ builder := func() {
|
|
|
1419
1543
|
|
|
1420
1544
|
if !is_undefined(gpuMemory) { quotaData.gpuMemory = gpuMemory }
|
|
1421
1545
|
}
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
scratchRequest := is_undefined(scratchFreeSpace) ? 0 : scratchFreeSpace
|
|
1562
|
+
if is_int(scratchRequest) { scratchRequest = string(scratchRequest) + "b" }
|
|
1563
|
+
quotaData.scratchFreeSpace = scratchRequest
|
|
1422
1564
|
metaExecInputs := {
|
|
1423
1565
|
quota: smart.createJsonResource(quotaData)
|
|
1424
1566
|
}
|
|
@@ -1442,6 +1584,7 @@ builder := func() {
|
|
|
1442
1584
|
if !is_undefined(resolvedMem) { metaExecInputs[execConstants.META_INPUT_MEM_FORMULA] = smart.createJsonResource(resolvedMem) }
|
|
1443
1585
|
if !is_undefined(resolvedCpu) { metaExecInputs[execConstants.META_INPUT_CPU_FORMULA] = smart.createJsonResource(resolvedCpu) }
|
|
1444
1586
|
if !is_undefined(resolvedGpu) { metaExecInputs[execConstants.META_INPUT_GPU_FORMULA] = smart.createJsonResource(resolvedGpu) }
|
|
1587
|
+
if !is_undefined(resolvedScratch) { metaExecInputs[execConstants.META_INPUT_SCRATCH_FORMULA] = smart.createJsonResource(resolvedScratch) }
|
|
1445
1588
|
if !is_undefined(lineCountMapResource) { pureExecInputs[execConstants.REGULAR_INPUT_LINE_COUNT] = lineCountMapResource }
|
|
1446
1589
|
|
|
1447
1590
|
|
|
@@ -1466,10 +1609,14 @@ builder := func() {
|
|
|
1466
1609
|
|
|
1467
1610
|
if !is_undefined(soft) {
|
|
1468
1611
|
pureExecInputs.softwareInfo = soft.resource
|
|
1612
|
+
descriptor := ll.fromStrict(soft.descriptor)
|
|
1613
|
+
if tmpdirCompatNeeded {
|
|
1614
|
+
descriptor = tmpdirCompat.patchSoftwareDescriptor(descriptor, feats.isDockerAvailable)
|
|
1615
|
+
}
|
|
1469
1616
|
pureExecInputs.runOptions.software = {
|
|
1470
1617
|
name: soft.name,
|
|
1471
1618
|
version: soft.version,
|
|
1472
|
-
descriptor:
|
|
1619
|
+
descriptor: descriptor
|
|
1473
1620
|
}
|
|
1474
1621
|
}
|
|
1475
1622
|
|
|
@@ -56,6 +56,7 @@ quotaBuilder := func() {
|
|
|
56
56
|
cpu_request := undefined
|
|
57
57
|
ram_request := undefined
|
|
58
58
|
gpu_request := undefined
|
|
59
|
+
scratch_request := undefined
|
|
59
60
|
|
|
60
61
|
self = ll.toStrict({
|
|
61
62
|
|
|
@@ -127,6 +128,33 @@ quotaBuilder := func() {
|
|
|
127
128
|
|
|
128
129
|
|
|
129
130
|
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
scratchFreeSpace: func(amount) {
|
|
139
|
+
validation.assertType(
|
|
140
|
+
amount,
|
|
141
|
+
["or", "number", "string", "null"],
|
|
142
|
+
"exec.quota.builder.scratchFreeSpace: scratch space amount should be a number or string")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
ll.assert(is_undefined(amount) || is_string(amount) || amount >= 0,
|
|
147
|
+
"exec.quota.builder.scratchFreeSpace: amount in bytes cannot be negative")
|
|
148
|
+
scratch_request = amount
|
|
149
|
+
|
|
150
|
+
return self
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
130
158
|
build: func() {
|
|
131
159
|
ll.assert(queue_name != "", "exec.quota.builder: queue name is mandatory and could not be empty string")
|
|
132
160
|
|
|
@@ -142,6 +170,9 @@ quotaBuilder := func() {
|
|
|
142
170
|
if !is_undefined(gpu_request) {
|
|
143
171
|
data.gpuMemory = gpu_request
|
|
144
172
|
}
|
|
173
|
+
if !is_undefined(scratch_request) {
|
|
174
|
+
data.scratchFreeSpace = scratch_request
|
|
175
|
+
}
|
|
145
176
|
|
|
146
177
|
return smart.ephemeralBuilder(_RTYPE_QUOTA, json.encode(data)).lockAndBuild()
|
|
147
178
|
}
|
|
@@ -0,0 +1,270 @@
|
|
|
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
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
31
|
+
text := import("text")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
SCRIPT_FILE_NAME := ".pl-run-compat-f9b7eca1b8.sh"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
SCRATCH_PATH_VARIABLE := "system.scratch.path"
|
|
50
|
+
SCRATCH_SIZE_VARIABLES := ["system.scratch.bytes", "system.scratch.gib", "system.scratch.kib",
|
|
51
|
+
"system.scratch.mib", "system.scratch.gb", "system.scratch.kb", "system.scratch.mb",
|
|
52
|
+
"system.scratch.b"]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
WORKDIR_TMP_REL_PATH := ".pl/tmp"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
script := func() {
|
|
65
|
+
return `#!/bin/sh
|
|
66
|
+
|
|
67
|
+
# Compatibility layer between a current workflow-tengo SDK and a Platforma Backend from before
|
|
68
|
+
# the temporary-directory contract. Update the backend and this file stops appearing here.
|
|
69
|
+
#
|
|
70
|
+
# Written by exec.tmpdirCompat in @platforma-sdk/workflow-tengo.
|
|
71
|
+
|
|
72
|
+
wd="${PL_JOB_WORKDIR:-$PWD}"
|
|
73
|
+
tmp="$wd/` + WORKDIR_TMP_REL_PATH + `"
|
|
74
|
+
mkdir -p "$tmp"
|
|
75
|
+
|
|
76
|
+
TMPDIR="$tmp"
|
|
77
|
+
TMP="$tmp"
|
|
78
|
+
export TMPDIR TMP
|
|
79
|
+
|
|
80
|
+
exec "$@"
|
|
81
|
+
`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
isNeeded := func(feats, scratchSized) {
|
|
93
|
+
if feats.supportsScratchSpaceRequests {
|
|
94
|
+
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if feats.hasScratchSpace {
|
|
99
|
+
|
|
100
|
+
return !scratchSized
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
return true
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
isSizedRequest := func(scratchFreeSpace, scratchFormulaAst) {
|
|
117
|
+
if !is_undefined(scratchFormulaAst) {
|
|
118
|
+
return true
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if is_undefined(scratchFreeSpace) {
|
|
122
|
+
return false
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return scratchFreeSpace != 0
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
isWindows := func() {
|
|
132
|
+
return ll.pathSeparator == "\\"
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
concat := func(prefix, tail) {
|
|
140
|
+
result := copy(prefix)
|
|
141
|
+
for item in tail {
|
|
142
|
+
result = append(result, item)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return result
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
_assertNotWindows := func() {
|
|
152
|
+
ll.assert(!isWindows(),
|
|
153
|
+
"exec.builder: this Platforma Backend is too old to provide a temporary directory (TMPDIR),"+
|
|
154
|
+
" and the workaround for it is POSIX-shell only, so it cannot run on Windows."+
|
|
155
|
+
" Update Platforma Backend to a version >=4.4.5")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
patchSoftwareDescriptor := func(descriptor, isDockerAvailable) {
|
|
170
|
+
if isDockerAvailable && !is_undefined(descriptor.docker) {
|
|
171
|
+
docker := ll.fromStrict(descriptor.docker)
|
|
172
|
+
|
|
173
|
+
entrypoint := docker.entrypoint
|
|
174
|
+
if is_undefined(entrypoint) { entrypoint = [] }
|
|
175
|
+
docker.entrypoint = concat(["sh", "./" + SCRIPT_FILE_NAME], entrypoint)
|
|
176
|
+
|
|
177
|
+
descriptor.docker = docker
|
|
178
|
+
return descriptor
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
_assertNotWindows()
|
|
184
|
+
|
|
185
|
+
for kind in ["local", "binary"] {
|
|
186
|
+
if is_undefined(descriptor[kind]) { continue }
|
|
187
|
+
|
|
188
|
+
pkg := ll.fromStrict(descriptor[kind])
|
|
189
|
+
ll.assert(is_array(pkg.cmd) && len(pkg.cmd) != 0,
|
|
190
|
+
"exec.tmpdirCompat: software descriptor %q has no 'cmd' to wrap", kind)
|
|
191
|
+
|
|
192
|
+
pkg.cmd = concat(["sh", "./" + SCRIPT_FILE_NAME], pkg.cmd)
|
|
193
|
+
descriptor[kind] = pkg
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return descriptor
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
wrapCommand := func(cmd) {
|
|
205
|
+
_assertNotWindows()
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
cmd: "sh",
|
|
209
|
+
prependArgs: ["./" + SCRIPT_FILE_NAME, cmd]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
rewriteScratchExpressions := func(value) {
|
|
233
|
+
if !is_string(value) {
|
|
234
|
+
return value
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
value = text.replace(value, "{" + SCRATCH_PATH_VARIABLE + "}", WORKDIR_TMP_REL_PATH, -1)
|
|
239
|
+
for variable in SCRATCH_SIZE_VARIABLES {
|
|
240
|
+
value = text.replace(value, "{" + variable + "}", "0", -1)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if !text.contains(value, "system.scratch.") {
|
|
244
|
+
return value
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
value = text.replace(value, SCRATCH_PATH_VARIABLE, "'" + WORKDIR_TMP_REL_PATH + "'", -1)
|
|
249
|
+
for variable in SCRATCH_SIZE_VARIABLES {
|
|
250
|
+
value = text.replace(value, variable, "0", -1)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return value
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export ll.toStrict({
|
|
257
|
+
SCRIPT_FILE_NAME: SCRIPT_FILE_NAME,
|
|
258
|
+
WORKDIR_TMP_REL_PATH: WORKDIR_TMP_REL_PATH,
|
|
259
|
+
SCRATCH_PATH_VARIABLE: SCRATCH_PATH_VARIABLE,
|
|
260
|
+
SCRATCH_SIZE_VARIABLES: SCRATCH_SIZE_VARIABLES,
|
|
261
|
+
|
|
262
|
+
script: script,
|
|
263
|
+
isNeeded: isNeeded,
|
|
264
|
+
isSizedRequest: isSizedRequest,
|
|
265
|
+
isWindows: isWindows,
|
|
266
|
+
patchSoftwareDescriptor: patchSoftwareDescriptor,
|
|
267
|
+
wrapCommand: wrapCommand,
|
|
268
|
+
rewriteScratchExpressions: rewriteScratchExpressions,
|
|
269
|
+
concat: concat
|
|
270
|
+
})
|
|
@@ -82,5 +82,17 @@ export ll.toStrict({
|
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
supportsScratchSpaceRequests: _isEnabled("supportsScratchSpaceRequests"),
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
hasScratchSpace: _isEnabled("scratchSpace"),
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
85
97
|
multiStepProgress: _isEnabled("multiStepProgress")
|
|
86
98
|
})
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/workflow-tengo",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.10.0",
|
|
4
4
|
"description": "Tengo SDK library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@platforma-open/milaboratories.software-ptexter": "1.2.4"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@platforma-sdk/tengo-builder": "4.0.
|
|
26
|
+
"@platforma-sdk/tengo-builder": "4.0.26"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"type-check": "pl-tengo check",
|