@platforma-sdk/workflow-tengo 2.8.1 → 2.8.2

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 (59) hide show
  1. package/dist/tengo/lib/assets.lib.tengo +76 -82
  2. package/dist/tengo/lib/constants.lib.tengo +28 -31
  3. package/dist/tengo/lib/exec.R.internal.lib.tengo +14 -14
  4. package/dist/tengo/lib/exec.R.lib.tengo +158 -167
  5. package/dist/tengo/lib/exec.internal.lib.tengo +222 -234
  6. package/dist/tengo/lib/exec.lib.tengo +647 -714
  7. package/dist/tengo/lib/exec.package.lib.tengo +229 -238
  8. package/dist/tengo/lib/exec.python.internal.lib.tengo +5 -6
  9. package/dist/tengo/lib/exec.python.lib.tengo +138 -146
  10. package/dist/tengo/lib/exec.runcmd.lib.tengo +234 -253
  11. package/dist/tengo/lib/exec.runenv.lib.tengo +88 -92
  12. package/dist/tengo/lib/exec.stream.lib.tengo +36 -40
  13. package/dist/tengo/lib/file.internal.lib.tengo +70 -77
  14. package/dist/tengo/lib/file.lib.tengo +54 -57
  15. package/dist/tengo/lib/ll.lib.tengo +217 -241
  16. package/dist/tengo/lib/maps.lib.tengo +98 -106
  17. package/dist/tengo/lib/objects.lib.tengo +11 -13
  18. package/dist/tengo/lib/oop.lib.tengo +16 -19
  19. package/dist/tengo/lib/path.lib.tengo +116 -125
  20. package/dist/tengo/lib/pframes.constants.lib.tengo +25 -28
  21. package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +28 -33
  22. package/dist/tengo/lib/pframes.lib.tengo +38 -43
  23. package/dist/tengo/lib/pframes.ll.lib.tengo +70 -73
  24. package/dist/tengo/lib/pframes.pcolumn.lib.tengo +45 -51
  25. package/dist/tengo/lib/pframes.spec.lib.tengo +70 -96
  26. package/dist/tengo/lib/pframes.util.lib.tengo +154 -289
  27. package/dist/tengo/lib/pframes.xsv.lib.tengo +260 -273
  28. package/dist/tengo/lib/render.lib.tengo +65 -76
  29. package/dist/tengo/lib/sets.lib.tengo +61 -68
  30. package/dist/tengo/lib/slices.lib.tengo +169 -180
  31. package/dist/tengo/lib/smart.lib.tengo +956 -1069
  32. package/dist/tengo/lib/test.lib.tengo +129 -161
  33. package/dist/tengo/lib/tpl.lib.tengo +448 -516
  34. package/dist/tengo/lib/tpl.state-await.lib.tengo +226 -241
  35. package/dist/tengo/lib/tpl.util.lib.tengo +4 -9
  36. package/dist/tengo/lib/validation.lib.tengo +334 -379
  37. package/dist/tengo/lib/workdir.lib.tengo +309 -332
  38. package/dist/tengo/lib/workdir.proc.lib.tengo +126 -144
  39. package/dist/tengo/lib/workdir.save.lib.tengo +113 -130
  40. package/dist/tengo/lib/workflow.bobject.lib.tengo +21 -26
  41. package/dist/tengo/lib/workflow.bquery.lib.tengo +140 -166
  42. package/dist/tengo/lib/workflow.constants.lib.tengo +1 -2
  43. package/dist/tengo/lib/workflow.context.lib.tengo +27 -32
  44. package/dist/tengo/lib/workflow.lib.tengo +167 -207
  45. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  46. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  47. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  48. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  49. package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
  50. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  51. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  52. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  53. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  54. package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
  55. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  56. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  57. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  58. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  59. package/package.json +5 -5
@@ -1,6 +1,5 @@
1
- /**
2
- * A builder for executing commands.
3
- */
1
+
2
+
4
3
 
5
4
  ll := import("@platforma-sdk/workflow-tengo:ll")
6
5
  assets := import("@platforma-sdk/workflow-tengo:assets")
@@ -21,719 +20,653 @@ _MEDIUM_QUEUE := "medium"
21
20
  _LIGHT_QUEUE := "light"
22
21
  _UI_TASKS_QUEUE := "ui-tasks"
23
22
 
24
- /**
25
- * Creates a new builder for constructing and executing commands.
26
- *
27
- * @return builder - a new builder instance.
28
- */
23
+
24
+
25
+
26
+
29
27
  builder := func() {
30
- self := undefined
31
-
32
- soft := undefined
33
- cmd := undefined
34
- args := []
35
- entrypointSet := false
36
-
37
- assertEntrypointNotSet := func() {
38
- ll.assert(!entrypointSet,
39
- "either a command with arguments or a software were already set.")
40
- }
41
-
42
- envs := {}
43
- secrets := {} // { "env_name": "{secrets.secret_name}", ... }
44
- queue := _HEAVY_QUEUE
45
- cache := 0
46
- nErrorLines := 200
47
-
48
- // files to be added in workdir
49
- filesToAdd := {}
50
- // files to be created in the workdir with the content from resources
51
- filesToWrite := {}
52
- // directories to create in the workdir
53
- dirsToCreate := {}
54
-
55
- // files to save from the workdir
56
- filesToSave := {}
57
- // files which content to save from the workdir
58
- filesContentToSave := {}
59
- // file sets to save by regex
60
- fileSetsToSave := {}
61
- // file sets to save by regex (save file content)
62
- fileSetsContentToSave := {}
63
- // files to stream from the workdir
64
- filesToStream := {}
65
- // workdir processors
66
- wdProcessors := {}
67
-
68
- // assets to be extracted into workdir before execution
69
- assetInfos := {}
70
- assetDescriptors := {}
71
- assetRules := {}
72
- assetCache := {}
73
-
74
- stdout := "stdout.txt"
75
- stderr := "stderr.txt"
76
-
77
- stdoutToValue := false
78
- stderrToValue := false
79
- stderrToStdout := false
80
-
81
- self = ll.toStrict({
82
- /**
83
- * Sets the command to be executed, e.g. /usr/bin/env or sh.
84
- *
85
- * @param commandName: string - the name of the command.
86
- */
87
- cmd: func(commandName) {
88
- assertEntrypointNotSet()
89
-
90
- cmd = commandName
91
- entrypointSet = true
92
- return self
93
- },
94
-
95
- /**
96
- * Sets the software to be executed.
97
- *
98
- * @param software: softwareInfo - the software to execute.
99
- */
100
- software: func(sw) {
101
- assertEntrypointNotSet()
102
- ll.assert(assets.isSoftwareInfo(sw),
103
- "exec.builder.software: <software> parameter is not a software info. Provide the value obtained from assets.importSoftware() here"
104
- )
105
-
106
- soft = sw
107
- entrypointSet = true
108
- return self
109
- },
110
-
111
- /**
112
- * Adds an argument to the command.
113
- *
114
- * @param arg: string - the argument to add.
115
- */
116
- arg: func(arg) {
117
- if is_undefined(arg) {
118
- ll.panic("exec: arg can't be undefined")
119
- }
120
- args = append(args, arg)
121
- return self
122
- },
123
-
124
- /**
125
- * Sets an environment variable.
126
- *
127
- * @param name: string - the name of the environment variable.
128
- * @param value: string - the value of the environment variable.
129
- */
130
- env: func(name, value) {
131
- validation.assertJsonSchema([name, value], ["string"])
132
- envs[name] = value
133
- return self
134
- },
135
-
136
- /**
137
- * Sets multiple environment variables.
138
- *
139
- * @param envMap: map[string]string - a map of environment variables.
140
- */
141
- envMap: func(envMap) {
142
- enum.each(envMap, self.env)
143
- return self
144
- },
145
-
146
- /**
147
- * Set environment variable to value of given secret.
148
- *
149
- * @param secretName: string - name of secret to pass as environment variable.
150
- * @param envName: string - name of environment variable to set with value of secret.
151
- */
152
- secret: func(secretName, envName) {
153
- validation.assertJsonSchema([secretName, envName], ["string"])
154
- secrets[envName] = "{secrets."+secretName+"}"
155
- return self
156
- },
157
-
158
- /**
159
- * Execute command in the 'heavy' queue.
160
- */
161
- inHeavyQueue: func() {
162
- queue = _HEAVY_QUEUE
163
- return self
164
- },
165
-
166
- /**
167
- * Execute command in the 'medium' queue.
168
- */
169
- inMediumQueue: func() {
170
- queue = _MEDIUM_QUEUE
171
- return self
172
- },
173
-
174
- /**
175
- * Execute command in the 'light' queue.
176
- */
177
- inLightQueue: func() {
178
- queue = _LIGHT_QUEUE
179
- return self
180
- },
181
-
182
- /**
183
- * Execute command in the 'ui-tasks' queue.
184
- */
185
- inUiQueue: func() {
186
- queue = _UI_TASKS_QUEUE
187
- return self
188
- },
189
-
190
- /**
191
- * Use cacheMillis, cacheSeconds, cacheMinutes, cacheHours and cacheDays to not make hidden mistakes in cache time ranges.
192
- * Sets the cache time.
193
- *
194
- * @param time: duration - the cache time from 'times' library.
195
- */
196
- cache: func(time) {
197
- ll.assert(
198
- is_int(time),
199
- "cache time must be an integer. " +
200
- "Did you forget to import a standard tengo library 'times'?")
201
- cache = time
202
- return self
203
- },
204
-
205
- /**
206
- * Sets the cache time in milliseconds.
207
- *
208
- * @param millis: number
209
- */
210
- cacheMillis: func(millis) {
211
- ll.assert(is_int(millis) && millis > 0, "cache time must be a number of milliseconds")
212
- cache = millis * times.millisecond
213
- return self
214
- },
215
-
216
- /**
217
- * Sets the cache time in seconds.
218
- *
219
- * @param seconds: number
220
- */
221
- cacheSeconds: func(seconds) {
222
- ll.assert(is_int(seconds) && seconds > 0, "cache time must be a number of seconds")
223
- cache = seconds * times.second
224
- return self
225
- },
226
-
227
- /**
228
- * Sets the cache time in minutes.
229
- *
230
- * @param minutes: number
231
- */
232
- cacheMinutes: func(minutes) {
233
- ll.assert(is_int(minutes) && minutes > 0, "cache time must be a number of minutes")
234
- cache = minutes * times.minute
235
- return self
236
- },
237
-
238
- /**
239
- * Sets the cache time in hours.
240
- *
241
- * @param hours: number
242
- */
243
- cacheHours: func(hours) {
244
- ll.assert(is_int(hours) && hours > 0, "cache time must be a number of hours")
245
- cache = hours * times.hour
246
- return self
247
- },
248
-
249
- /**
250
- * Sets the cache time in days
251
- *
252
- * @param days: number
253
- */
254
- cacheDays: func(days) {
255
- ll.assert(is_int(days) && days > 0, "cache time must be a number of days")
256
- cache = days * times.hour * 24
257
- return self
258
- },
259
-
260
- /**
261
- * Sets the number of error lines to be captured.
262
- *
263
- * @param lines: number - the number of error lines.
264
- */
265
- nErrorLines: func(lines) {
266
- ll.assert(
267
- is_int(lines) && lines >= 0,
268
- "lines must be integer")
269
-
270
- nErrorLines = lines
271
- return self
272
- },
273
-
274
- /**
275
- * Adds files from given asset into working directory.
276
- *
277
- * @param asset: assetInfo - asset info loaded from assets.importAsset()
278
- * @param destinationDir: string - path inside working directory for files to be extracted from archive. Use "." for root of the workdir.
279
- * @param pathsInArchive: string[] - paths inside the archive to be extracted into destinationDir.
280
- * Empty array means 'unpack full archive'.
281
- */
282
- addAsset: func(asset, destinationDir, ...pathsInArchive) {
283
- if (len(pathsInArchive) == 1 && is_array(pathsInArchive[0])) {
284
- // support [<paths>] single argument
285
- pathsInArchive = pathsInArchive[0]
286
- }
287
- if len(pathsInArchive) == 0 {
288
- // default for 'no paths' is to extract all
289
- pathsInArchive = []
290
- }
291
-
292
- ll.assert(assets.isAssetInfo(asset),
293
- "exec.builder.addAsset: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
294
- validation.assertJsonSchema(destinationDir, "string", "exec.builder.addAsset: <destinationDir> is not a string. It must be a path inside working directory")
295
- validation.assertJsonSchema(pathsInArchive, ["string"], "exec.builder.addAsset: <pathsInArchive> must contain list of strings with paths inside archive")
296
-
297
- assetIdKey := ll.idToString(asset._id)
298
- if is_undefined(assetRules[assetIdKey]) {
299
- assetInfos[assetIdKey] = asset.resource
300
- assetDescriptors[assetIdKey] = ll.fromStrict(asset.descriptor)
301
- assetRules[assetIdKey] = {}
302
- }
303
-
304
- if len(pathsInArchive) == 0 || is_undefined(assetRules[assetIdKey][destinationDir]) {
305
- assetRules[assetIdKey][destinationDir] = []
306
- }
307
-
308
- if (len(pathsInArchive) > 0) {
309
- assetRules[assetIdKey][destinationDir] = append(assetRules[assetIdKey][destinationDir], pathsInArchive...)
310
- }
311
-
312
- return self
313
- },
314
-
315
- /**
316
- * Set custom cache time for given asset. By default, cache time of 1 day is applied to all assets.
317
- * This allows to customize cache time on per-asset basis
318
- */
319
- cacheAssetMillis: func (asset, millis) {
320
- ll.assert(assets.isAssetInfo(asset),
321
- "exec.builder.cacheAssetMillis: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
322
- ll.assert(is_int(millis),
323
- "exec.builder.cacheAssetMillis: asset cache time must be a number of milliseconds.")
324
-
325
- assetIdKey := ll.idToString(asset._id)
326
- assetCache[assetIdKey] = millis * times.millisecond
327
-
328
- return self
329
- },
330
-
331
- /**
332
- * Set custom cache time for given asset. By default, cache time of 1 day is applied to all assets.
333
- * This allows to customize cache time on per-asset basis
334
- */
335
- cacheAssetSeconds: func (asset, seconds) {
336
- ll.assert(assets.isAssetInfo(asset),
337
- "exec.builder.cacheAssetSeconds: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
338
- ll.assert(is_int(seconds),
339
- "exec.builder.cacheAssetSeconds: asset cache time must be a number of seconds.")
340
-
341
- assetIdKey := ll.idToString(asset._id)
342
- assetCache[assetIdKey] = seconds * times.second
343
-
344
- return self
345
- },
346
-
347
- /**
348
- * Set custom cache time for given asset. By default, cache time of 1 day is applied to all assets.
349
- * This allows to customize cache time on per-asset basis
350
- */
351
- cacheAssetMinutes: func (asset, minutes) {
352
- ll.assert(assets.isAssetInfo(asset),
353
- "exec.builder.cacheAssetMinutes: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
354
- ll.assert(is_int(minutes),
355
- "exec.builder.cacheAssetMinutes: asset cache time must be a number of minutes.")
356
-
357
- assetIdKey := ll.idToString(asset._id)
358
- assetCache[assetIdKey] = minutes * times.minute
359
-
360
- return self
361
- },
362
-
363
- /**
364
- * Set custom cache time for given asset. By default, cache time of 1 day is applied to all assets.
365
- * This allows to customize cache time on per-asset basis
366
- */
367
- cacheAssetHours: func (asset, hours) {
368
- ll.assert(assets.isAssetInfo(asset),
369
- "exec.builder.cacheAssetHours: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
370
- ll.assert(is_int(hours),
371
- "exec.builder.cacheAssetHours: asset cache time must be a number of hours.")
372
-
373
- assetIdKey := ll.idToString(asset._id)
374
- assetCache[assetIdKey] = hours * times.hour
375
-
376
- return self
377
- },
378
-
379
- /**
380
- * Set custom cache time for given asset. By default, cache time of 1 day is applied to all assets.
381
- * This allows to customize cache time on per-asset basis
382
- */
383
- cacheAssetDays: func (asset, days) {
384
- ll.assert(assets.isAssetInfo(asset),
385
- "exec.builder.cacheAssetHours: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
386
- ll.assert(is_int(days),
387
- "exec.builder.cacheAssetHours: asset cache time must be a number of days.")
388
-
389
- assetIdKey := ll.idToString(asset._id)
390
- assetCache[assetIdKey] = days * 24 * times.hour
391
-
392
- return self
393
- },
394
-
395
- /**
396
- * Adds a file to the working directory
397
- *
398
- * @param fileName: string - the name of the input file.
399
- * @param file: reference - a resource id of the file or a field that points to it.
400
- */
401
- addFile: func(fileName, file) {
402
- fileName = path.canonize(fileName)
403
- filesToAdd[fileName] = file
404
- return self
405
- },
406
-
407
- /**
408
- * Adds multiple files to the working directory.
409
- *
410
- * @param filesMap: map[string]reference - a map of file names to files' references.
411
- */
412
- addFiles: func(filesMap) {
413
- enum.each(filesMap, self.addFile)
414
- return self
415
- },
416
-
417
- /**
418
- * Writes a file with a given content.
419
- *
420
- * @param fileName: string - the name of the content.
421
- * @param data: bytes|reference - a primitive tengo value (map or array) or a reference to
422
- * a resource from which data we create a file.
423
- */
424
- writeFile: func(fileName, data) {
425
- validation.assertJsonSchema(data, ["or",
426
- "string",
427
- "bytes",
428
- validation.reference])
429
-
430
- fileName = path.canonize(fileName)
431
-
432
- filesToWrite[fileName] = data
433
-
434
- return self
435
- },
436
-
437
- /**
438
- * Creates a directory.
439
- *
440
- * @param dir: string - the directory to create.
441
- */
442
- mkDir: func(dir) {
443
- dir = path.canonize(dir)
444
- dirsToCreate = sets.add(dirsToCreate, dir)
445
- return self
446
- },
447
-
448
- /**
449
- * Saves a file.
450
- *
451
- * @param fileName: string - the name of the output file.
452
- */
453
- saveFile: func(fileName) {
454
- fileName = path.canonize(fileName)
455
- sets.add(filesToSave, fileName)
456
- return self
457
- },
458
-
459
- /**
460
- * Saves a file's content to a value resource.
461
- *
462
- * @param fileName: string - the name of the output value.
463
- */
464
- saveFileContent: func(fileName) {
465
- fileName = path.canonize(fileName)
466
- sets.add(filesContentToSave, fileName)
467
- return self
468
- },
469
-
470
- /**
471
- * Saves files from the exec workdir using regex.
472
- *
473
- * @param name: string - a name to refer this file set in the outputs
474
- * @param regex: string - regex pattern
475
- */
476
- saveFileSet: func(name, regex) {
477
- fileSetsToSave[name] = regex
478
- return self
479
- },
480
-
481
- /**
482
- * Run specified
483
- */
484
- processWorkdir: func(name, tpl, tplArgs) {
485
- wdProcessors[name] = {
486
- tpl: tpl,
487
- tplArgs: tplArgs
488
- }
489
- return self
490
- },
491
-
492
- /**
493
- * Saves files content from the exec workdir using regex.
494
- *
495
- * @param name: string - a name to refer this file set in the outputs
496
- * @param regex: string - regex pattern
497
- */
498
- saveFileSetContent: func(name, regex) {
499
- fileSetsContentToSave[name] = regex
500
- return self
501
- },
502
-
503
- /**
504
- * A command to stream a file by a given file name.
505
- *
506
- * @param fileName: string - the name of the file to stream.
507
- */
508
- streamFile: func(fileName) {
509
- fileName = path.canonize(fileName)
510
- sets.add(filesToStream, fileName)
511
-
512
- return self
513
- },
514
-
515
- /**
516
- * Set stdout file name
517
- */
518
- stdoutFileName: func(fileName) {
519
- fileName = path.canonize(fileName)
520
- stdout = fileName
521
- return self
522
- },
523
-
524
- /**
525
- * Set stderr file name
526
- */
527
- stderrFileName: func(fileName) {
528
- fileName = path.canonize(fileName)
529
- stderr = fileName
530
- return self
531
- },
532
-
533
- /**
534
- * Sets stdout to be captured as a value resource.
535
- */
536
- saveStdoutContent: func() {
537
- stdoutToValue = true
538
- return self
539
- },
540
-
541
- /**
542
- * Sets stderr to be captured as a value resource.
543
- */
544
- saveStderrContent: func() {
545
- stderrToValue = true
546
- return self
547
- },
548
-
549
- /**
550
- * Redirects stderr output to stdout.
551
- */
552
- printErrStreamToStdout: func() {
553
- stderrToStdout = true
554
- return self
555
- },
556
-
557
- /**
558
- * Executes the command.
559
- *
560
- * @return A map containing the execution results.
561
- */
562
- run: func() {
563
- if stderrToStdout {
564
- stderr = stdout
565
- }
566
- sets.add(filesToStream, stdout)
567
- sets.add(filesToStream, stderr)
568
- sets.add(filesToSave, stdout)
569
- sets.add(filesToSave, stderr)
570
- if stdoutToValue {
571
- sets.add(filesContentToSave, stdout)
572
- }
573
- if stderrToValue {
574
- sets.add(filesContentToSave, stderr)
575
- }
576
-
577
- // We don't want these values to be encoded as JSON's since
578
- // values are pure bytes.
579
- // Thus, we create a resource with a custom type here manually.
580
- filesToWriteRefs := maps.mapValues(filesToWrite, func(v) {
581
- if smart.isReference(v) { return v }
582
- return smart.createValueResource(constants.RTYPE_BINARY_VALUE, v)
583
- })
584
-
585
- ll.assert(entrypointSet,
586
- "incomplete command: cmd() or software() must be provided to exec.builder")
587
-
588
- execInputs := {
589
- filesToAdd: smart.createMapResource(filesToAdd),
590
- filesToWrite: smart.createMapResource(filesToWriteRefs),
591
- dirsToCreate: slices.fromSet(dirsToCreate),
592
- runOptions: {
593
- cmd: cmd,
594
- args: args,
595
- envs: envs,
596
- secrets: secrets,
597
- queue: queue,
598
- stdout: stdout,
599
- stderr: stderr,
600
- nErrorLines: nErrorLines
601
- },
602
- filesToSave: slices.fromSet(filesToSave),
603
- filesContentToSave: slices.fromSet(filesContentToSave),
604
- fileSetsToSave: fileSetsToSave,
605
- fileSetsContentToSave: fileSetsContentToSave,
606
- filesToStream: slices.fromSet(filesToStream),
607
- wdProcessors: wdProcessors,
608
- assets: smart.createMapResource(assetInfos),
609
- assetDescriptors: assetDescriptors,
610
- assetRules: assetRules,
611
- assetCache: assetCache
612
- }
613
-
614
- if !is_undefined(soft) {
615
- execInputs.softwareInfo = soft.resource
616
- execInputs.runOptions.software = {
617
- name: soft.name,
618
- version: soft.version,
619
- descriptor: ll.fromStrict(soft.descriptor)
620
- }
621
- }
622
-
623
- tpl := render.create(assets.importTemplate("@platforma-sdk/workflow-tengo:exec.exec"), execInputs)
624
-
625
- self := undefined
626
- self = ll.toStrict(oop.inherit(tpl, {
627
- /**
628
- * Retrieves a file.
629
- *
630
- * @param fileName: string
631
- * @return field - a reference to the file resource.
632
- */
633
- getFile: func(fileName) {
634
- return tpl.output("files", cache).getFutureInputField(fileName)
635
- },
636
-
637
- /**
638
- * Retrieves the content of a file.
639
- *
640
- * @param fileName: string
641
- * @return field - a reference to the file content resource.
642
- */
643
- getFileContent: func(fileName) {
644
- return tpl.output("filesContent", cache).getFutureInputField(fileName)
645
- },
646
-
647
- /**
648
- * Retrieves a file stream.
649
- *
650
- * @param fileName: string
651
- * @return field - a reference to the file stream resource.
652
- */
653
- getFileStream: func(fileName) {
654
- return tpl.output("fileStreams", cache).getFutureInputField(fileName, true)
655
- },
656
-
657
- /**
658
- * Retrieves a file set resource.
659
- *
660
- * @param fileSetName: string - name of a file set
661
- * @return field - a reference to the map resource with files
662
- */
663
- getFileSet: func(fileSetName) {
664
- return tpl.output("fileSets", cache).getFutureInputField(fileSetName)
665
- },
666
-
667
- /**
668
- * Retrieves a file set content resource.
669
- *
670
- * @param fileSetName: string - name of a file set
671
- * @return field - a reference to the map resource with files
672
- */
673
- getFileSetContent: func(fileSetName) {
674
- return tpl.output("fileSetsContent", cache).getFutureInputField(fileSetName)
675
- },
676
-
677
- getProcessorResult: func(procName) {
678
- return tpl.output("wdProcessors", cache).getFutureInputField(procName)
679
- },
680
-
681
- /**
682
- * Retrieves the stdout stream.
683
- */
684
- getStdoutStream: func() {
685
- return self.getFileStream(stdout)
686
- },
687
-
688
- /**
689
- * Retrieves the stderr stream.
690
- */
691
- getStderrStream: func() {
692
- return self.getFileStream(stderr)
693
- },
694
-
695
- /**
696
- * Retrieves the stdout file.
697
- */
698
- getStdoutFile: func() {
699
- return self.getFile(stdout)
700
- },
701
-
702
- /**
703
- * Retrieves the stderr file.
704
- */
705
- getStderrFile: func() {
706
- return self.getFile(stderr)
707
- },
708
-
709
- /**
710
- * Retrieves the content of the stdout file.
711
- */
712
- getStdoutFileContent: func() {
713
- if stdoutToValue {
714
- return self.getFileContent(stdout)
715
- }
716
- ll.panic("stdout was not saved as a content")
717
- },
718
-
719
- /**
720
- * Retrieves the content of the stderr file.
721
- */
722
- getStderrFileContent: func() {
723
- if stderrToValue {
724
- return self.getFileContent(stderr)
725
- }
726
- ll.panic("stderr was not saved as a content")
727
- }
728
- }))
729
-
730
- return self
731
- }
732
- })
733
-
734
- return self
28
+ self := undefined
29
+
30
+ soft := undefined
31
+ cmd := undefined
32
+ args := []
33
+ entrypointSet := false
34
+
35
+ assertEntrypointNotSet := func() {
36
+ ll.assert(!entrypointSet,
37
+ "either a command with arguments or a software were already set.")
38
+ }
39
+
40
+ envs := {}
41
+ secrets := {} // { "env_name": "{secrets.secret_name}", ... }
42
+ queue := _HEAVY_QUEUE
43
+ cache := 0
44
+ nErrorLines := 200
45
+
46
+ filesToAdd := {}
47
+ filesToWrite := {}
48
+ dirsToCreate := {}
49
+
50
+ filesToSave := {}
51
+ filesContentToSave := {}
52
+ fileSetsToSave := {}
53
+ fileSetsContentToSave := {}
54
+ filesToStream := {}
55
+ wdProcessors := {}
56
+
57
+ assetInfos := {}
58
+ assetDescriptors := {}
59
+ assetRules := {}
60
+ assetCache := {}
61
+
62
+ stdout := "stdout.txt"
63
+ stderr := "stderr.txt"
64
+
65
+ stdoutToValue := false
66
+ stderrToValue := false
67
+ stderrToStdout := false
68
+
69
+ self = ll.toStrict({
70
+
71
+
72
+
73
+
74
+ cmd: func(commandName) {
75
+ assertEntrypointNotSet()
76
+
77
+ cmd = commandName
78
+ entrypointSet = true
79
+ return self
80
+ },
81
+
82
+
83
+
84
+
85
+
86
+ software: func(sw) {
87
+ assertEntrypointNotSet()
88
+ ll.assert(assets.isSoftwareInfo(sw),
89
+ "exec.builder.software: <software> parameter is not a software info. Provide the value obtained from assets.importSoftware() here"
90
+ )
91
+
92
+ soft = sw
93
+ entrypointSet = true
94
+ return self
95
+ },
96
+
97
+
98
+
99
+
100
+
101
+ arg: func(arg) {
102
+ if is_undefined(arg) {
103
+ ll.panic("exec: arg can't be undefined")
104
+ }
105
+ args = append(args, arg)
106
+ return self
107
+ },
108
+
109
+
110
+
111
+
112
+
113
+
114
+ env: func(name, value) {
115
+ validation.assertJsonSchema([name, value], ["string"])
116
+ envs[name] = value
117
+ return self
118
+ },
119
+
120
+
121
+
122
+
123
+
124
+ envMap: func(envMap) {
125
+ enum.each(envMap, self.env)
126
+ return self
127
+ },
128
+
129
+
130
+
131
+
132
+
133
+
134
+ secret: func(secretName, envName) {
135
+ validation.assertJsonSchema([secretName, envName], ["string"])
136
+ secrets[envName] = "{secrets."+secretName+"}"
137
+ return self
138
+ },
139
+
140
+
141
+
142
+ inHeavyQueue: func() {
143
+ queue = _HEAVY_QUEUE
144
+ return self
145
+ },
146
+
147
+
148
+
149
+ inMediumQueue: func() {
150
+ queue = _MEDIUM_QUEUE
151
+ return self
152
+ },
153
+
154
+
155
+
156
+ inLightQueue: func() {
157
+ queue = _LIGHT_QUEUE
158
+ return self
159
+ },
160
+
161
+
162
+
163
+ inUiQueue: func() {
164
+ queue = _UI_TASKS_QUEUE
165
+ return self
166
+ },
167
+
168
+
169
+
170
+
171
+
172
+
173
+ cache: func(time) {
174
+ ll.assert(
175
+ is_int(time),
176
+ "cache time must be an integer. " +
177
+ "Did you forget to import a standard tengo library 'times'?")
178
+ cache = time
179
+ return self
180
+ },
181
+
182
+
183
+
184
+
185
+
186
+ cacheMillis: func(millis) {
187
+ ll.assert(is_int(millis) && millis > 0, "cache time must be a number of milliseconds")
188
+ cache = millis * times.millisecond
189
+ return self
190
+ },
191
+
192
+
193
+
194
+
195
+
196
+ cacheSeconds: func(seconds) {
197
+ ll.assert(is_int(seconds) && seconds > 0, "cache time must be a number of seconds")
198
+ cache = seconds * times.second
199
+ return self
200
+ },
201
+
202
+
203
+
204
+
205
+
206
+ cacheMinutes: func(minutes) {
207
+ ll.assert(is_int(minutes) && minutes > 0, "cache time must be a number of minutes")
208
+ cache = minutes * times.minute
209
+ return self
210
+ },
211
+
212
+
213
+
214
+
215
+
216
+ cacheHours: func(hours) {
217
+ ll.assert(is_int(hours) && hours > 0, "cache time must be a number of hours")
218
+ cache = hours * times.hour
219
+ return self
220
+ },
221
+
222
+
223
+
224
+
225
+
226
+ cacheDays: func(days) {
227
+ ll.assert(is_int(days) && days > 0, "cache time must be a number of days")
228
+ cache = days * times.hour * 24
229
+ return self
230
+ },
231
+
232
+
233
+
234
+
235
+
236
+ nErrorLines: func(lines) {
237
+ ll.assert(
238
+ is_int(lines) && lines >= 0,
239
+ "lines must be integer")
240
+
241
+ nErrorLines = lines
242
+ return self
243
+ },
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+ addAsset: func(asset, destinationDir, ...pathsInArchive) {
253
+ if (len(pathsInArchive) == 1 && is_array(pathsInArchive[0])) {
254
+ pathsInArchive = pathsInArchive[0]
255
+ }
256
+ if len(pathsInArchive) == 0 {
257
+ pathsInArchive = []
258
+ }
259
+
260
+ ll.assert(assets.isAssetInfo(asset),
261
+ "exec.builder.addAsset: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
262
+ validation.assertJsonSchema(destinationDir, "string", "exec.builder.addAsset: <destinationDir> is not a string. It must be a path inside working directory")
263
+ validation.assertJsonSchema(pathsInArchive, ["string"], "exec.builder.addAsset: <pathsInArchive> must contain list of strings with paths inside archive")
264
+
265
+ assetIdKey := ll.idToString(asset._id)
266
+ if is_undefined(assetRules[assetIdKey]) {
267
+ assetInfos[assetIdKey] = asset.resource
268
+ assetDescriptors[assetIdKey] = ll.fromStrict(asset.descriptor)
269
+ assetRules[assetIdKey] = {}
270
+ }
271
+
272
+ if len(pathsInArchive) == 0 || is_undefined(assetRules[assetIdKey][destinationDir]) {
273
+ assetRules[assetIdKey][destinationDir] = []
274
+ }
275
+
276
+ if (len(pathsInArchive) > 0) {
277
+ assetRules[assetIdKey][destinationDir] = append(assetRules[assetIdKey][destinationDir], pathsInArchive...)
278
+ }
279
+
280
+ return self
281
+ },
282
+
283
+
284
+
285
+
286
+ cacheAssetMillis: func (asset, millis) {
287
+ ll.assert(assets.isAssetInfo(asset),
288
+ "exec.builder.cacheAssetMillis: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
289
+ ll.assert(is_int(millis),
290
+ "exec.builder.cacheAssetMillis: asset cache time must be a number of milliseconds.")
291
+
292
+ assetIdKey := ll.idToString(asset._id)
293
+ assetCache[assetIdKey] = millis * times.millisecond
294
+
295
+ return self
296
+ },
297
+
298
+
299
+
300
+
301
+ cacheAssetSeconds: func (asset, seconds) {
302
+ ll.assert(assets.isAssetInfo(asset),
303
+ "exec.builder.cacheAssetSeconds: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
304
+ ll.assert(is_int(seconds),
305
+ "exec.builder.cacheAssetSeconds: asset cache time must be a number of seconds.")
306
+
307
+ assetIdKey := ll.idToString(asset._id)
308
+ assetCache[assetIdKey] = seconds * times.second
309
+
310
+ return self
311
+ },
312
+
313
+
314
+
315
+
316
+ cacheAssetMinutes: func (asset, minutes) {
317
+ ll.assert(assets.isAssetInfo(asset),
318
+ "exec.builder.cacheAssetMinutes: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
319
+ ll.assert(is_int(minutes),
320
+ "exec.builder.cacheAssetMinutes: asset cache time must be a number of minutes.")
321
+
322
+ assetIdKey := ll.idToString(asset._id)
323
+ assetCache[assetIdKey] = minutes * times.minute
324
+
325
+ return self
326
+ },
327
+
328
+
329
+
330
+
331
+ cacheAssetHours: func (asset, hours) {
332
+ ll.assert(assets.isAssetInfo(asset),
333
+ "exec.builder.cacheAssetHours: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
334
+ ll.assert(is_int(hours),
335
+ "exec.builder.cacheAssetHours: asset cache time must be a number of hours.")
336
+
337
+ assetIdKey := ll.idToString(asset._id)
338
+ assetCache[assetIdKey] = hours * times.hour
339
+
340
+ return self
341
+ },
342
+
343
+
344
+
345
+
346
+ cacheAssetDays: func (asset, days) {
347
+ ll.assert(assets.isAssetInfo(asset),
348
+ "exec.builder.cacheAssetHours: <asset> parameter is not an asset info. Provide the value obtained from assets.importAsset() here")
349
+ ll.assert(is_int(days),
350
+ "exec.builder.cacheAssetHours: asset cache time must be a number of days.")
351
+
352
+ assetIdKey := ll.idToString(asset._id)
353
+ assetCache[assetIdKey] = days * 24 * times.hour
354
+
355
+ return self
356
+ },
357
+
358
+
359
+
360
+
361
+
362
+
363
+ addFile: func(fileName, file) {
364
+ fileName = path.canonize(fileName)
365
+ filesToAdd[fileName] = file
366
+ return self
367
+ },
368
+
369
+
370
+
371
+
372
+
373
+ addFiles: func(filesMap) {
374
+ enum.each(filesMap, self.addFile)
375
+ return self
376
+ },
377
+
378
+
379
+
380
+
381
+
382
+
383
+
384
+ writeFile: func(fileName, data) {
385
+ validation.assertJsonSchema(data, ["or",
386
+ "string",
387
+ "bytes",
388
+ validation.reference])
389
+
390
+ fileName = path.canonize(fileName)
391
+
392
+ filesToWrite[fileName] = data
393
+
394
+ return self
395
+ },
396
+
397
+
398
+
399
+
400
+
401
+ mkDir: func(dir) {
402
+ dir = path.canonize(dir)
403
+ dirsToCreate = sets.add(dirsToCreate, dir)
404
+ return self
405
+ },
406
+
407
+
408
+
409
+
410
+
411
+ saveFile: func(fileName) {
412
+ fileName = path.canonize(fileName)
413
+ sets.add(filesToSave, fileName)
414
+ return self
415
+ },
416
+
417
+
418
+
419
+
420
+
421
+ saveFileContent: func(fileName) {
422
+ fileName = path.canonize(fileName)
423
+ sets.add(filesContentToSave, fileName)
424
+ return self
425
+ },
426
+
427
+
428
+
429
+
430
+
431
+
432
+ saveFileSet: func(name, regex) {
433
+ fileSetsToSave[name] = regex
434
+ return self
435
+ },
436
+
437
+
438
+
439
+ processWorkdir: func(name, tpl, tplArgs) {
440
+ wdProcessors[name] = {
441
+ tpl: tpl,
442
+ tplArgs: tplArgs
443
+ }
444
+ return self
445
+ },
446
+
447
+
448
+
449
+
450
+
451
+
452
+ saveFileSetContent: func(name, regex) {
453
+ fileSetsContentToSave[name] = regex
454
+ return self
455
+ },
456
+
457
+
458
+
459
+
460
+
461
+ streamFile: func(fileName) {
462
+ fileName = path.canonize(fileName)
463
+ sets.add(filesToStream, fileName)
464
+
465
+ return self
466
+ },
467
+
468
+
469
+
470
+ stdoutFileName: func(fileName) {
471
+ fileName = path.canonize(fileName)
472
+ stdout = fileName
473
+ return self
474
+ },
475
+
476
+
477
+
478
+ stderrFileName: func(fileName) {
479
+ fileName = path.canonize(fileName)
480
+ stderr = fileName
481
+ return self
482
+ },
483
+
484
+
485
+
486
+ saveStdoutContent: func() {
487
+ stdoutToValue = true
488
+ return self
489
+ },
490
+
491
+
492
+
493
+ saveStderrContent: func() {
494
+ stderrToValue = true
495
+ return self
496
+ },
497
+
498
+
499
+
500
+ printErrStreamToStdout: func() {
501
+ stderrToStdout = true
502
+ return self
503
+ },
504
+
505
+
506
+
507
+
508
+
509
+ run: func() {
510
+ if stderrToStdout {
511
+ stderr = stdout
512
+ }
513
+ sets.add(filesToStream, stdout)
514
+ sets.add(filesToStream, stderr)
515
+ sets.add(filesToSave, stdout)
516
+ sets.add(filesToSave, stderr)
517
+ if stdoutToValue {
518
+ sets.add(filesContentToSave, stdout)
519
+ }
520
+ if stderrToValue {
521
+ sets.add(filesContentToSave, stderr)
522
+ }
523
+
524
+ filesToWriteRefs := maps.mapValues(filesToWrite, func(v) {
525
+ if smart.isReference(v) { return v }
526
+ return smart.createValueResource(constants.RTYPE_BINARY_VALUE, v)
527
+ })
528
+
529
+ ll.assert(entrypointSet,
530
+ "incomplete command: cmd() or software() must be provided to exec.builder")
531
+
532
+ execInputs := {
533
+ filesToAdd: smart.createMapResource(filesToAdd),
534
+ filesToWrite: smart.createMapResource(filesToWriteRefs),
535
+ dirsToCreate: slices.fromSet(dirsToCreate),
536
+ runOptions: {
537
+ cmd: cmd,
538
+ args: args,
539
+ envs: envs,
540
+ secrets: secrets,
541
+ queue: queue,
542
+ stdout: stdout,
543
+ stderr: stderr,
544
+ nErrorLines: nErrorLines
545
+ },
546
+ filesToSave: slices.fromSet(filesToSave),
547
+ filesContentToSave: slices.fromSet(filesContentToSave),
548
+ fileSetsToSave: fileSetsToSave,
549
+ fileSetsContentToSave: fileSetsContentToSave,
550
+ filesToStream: slices.fromSet(filesToStream),
551
+ wdProcessors: wdProcessors,
552
+ assets: smart.createMapResource(assetInfos),
553
+ assetDescriptors: assetDescriptors,
554
+ assetRules: assetRules,
555
+ assetCache: assetCache
556
+ }
557
+
558
+ if !is_undefined(soft) {
559
+ execInputs.softwareInfo = soft.resource
560
+ execInputs.runOptions.software = {
561
+ name: soft.name,
562
+ version: soft.version,
563
+ descriptor: ll.fromStrict(soft.descriptor)
564
+ }
565
+ }
566
+
567
+ tpl := render.create(assets.importTemplate("@platforma-sdk/workflow-tengo:exec.exec"), execInputs)
568
+
569
+ self := undefined
570
+ self = ll.toStrict(oop.inherit(tpl, {
571
+
572
+
573
+
574
+
575
+
576
+ getFile: func(fileName) {
577
+ return tpl.output("files", cache).getFutureInputField(fileName)
578
+ },
579
+
580
+
581
+
582
+
583
+
584
+
585
+ getFileContent: func(fileName) {
586
+ return tpl.output("filesContent", cache).getFutureInputField(fileName)
587
+ },
588
+
589
+
590
+
591
+
592
+
593
+
594
+ getFileStream: func(fileName) {
595
+ return tpl.output("fileStreams", cache).getFutureInputField(fileName, true)
596
+ },
597
+
598
+
599
+
600
+
601
+
602
+
603
+ getFileSet: func(fileSetName) {
604
+ return tpl.output("fileSets", cache).getFutureInputField(fileSetName)
605
+ },
606
+
607
+
608
+
609
+
610
+
611
+
612
+ getFileSetContent: func(fileSetName) {
613
+ return tpl.output("fileSetsContent", cache).getFutureInputField(fileSetName)
614
+ },
615
+
616
+ getProcessorResult: func(procName) {
617
+ return tpl.output("wdProcessors", cache).getFutureInputField(procName)
618
+ },
619
+
620
+
621
+
622
+ getStdoutStream: func() {
623
+ return self.getFileStream(stdout)
624
+ },
625
+
626
+
627
+
628
+ getStderrStream: func() {
629
+ return self.getFileStream(stderr)
630
+ },
631
+
632
+
633
+
634
+ getStdoutFile: func() {
635
+ return self.getFile(stdout)
636
+ },
637
+
638
+
639
+
640
+ getStderrFile: func() {
641
+ return self.getFile(stderr)
642
+ },
643
+
644
+
645
+
646
+ getStdoutFileContent: func() {
647
+ if stdoutToValue {
648
+ return self.getFileContent(stdout)
649
+ }
650
+ ll.panic("stdout was not saved as a content")
651
+ },
652
+
653
+
654
+
655
+ getStderrFileContent: func() {
656
+ if stderrToValue {
657
+ return self.getFileContent(stderr)
658
+ }
659
+ ll.panic("stderr was not saved as a content")
660
+ }
661
+ }))
662
+
663
+ return self
664
+ }
665
+ })
666
+
667
+ return self
735
668
  }
736
669
 
737
670
  export ll.toStrict({
738
- builder: builder
671
+ builder: builder
739
672
  })