hpcflow-new2 0.2.0a190__py3-none-any.whl → 0.2.0a200__py3-none-any.whl
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.
- hpcflow/__pyinstaller/hook-hpcflow.py +1 -0
- hpcflow/_version.py +1 -1
- hpcflow/data/scripts/bad_script.py +2 -0
- hpcflow/data/scripts/do_nothing.py +2 -0
- hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
- hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/input_file_generator_basic.py +3 -0
- hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
- hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
- hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
- hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
- hpcflow/data/scripts/output_file_parser_basic.py +3 -0
- hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
- hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/script_exit_test.py +5 -0
- hpcflow/data/template_components/environments.yaml +1 -1
- hpcflow/sdk/__init__.py +5 -0
- hpcflow/sdk/app.py +166 -92
- hpcflow/sdk/cli.py +263 -84
- hpcflow/sdk/cli_common.py +99 -5
- hpcflow/sdk/config/callbacks.py +38 -1
- hpcflow/sdk/config/config.py +102 -13
- hpcflow/sdk/config/errors.py +19 -5
- hpcflow/sdk/config/types.py +3 -0
- hpcflow/sdk/core/__init__.py +25 -1
- hpcflow/sdk/core/actions.py +914 -262
- hpcflow/sdk/core/cache.py +76 -34
- hpcflow/sdk/core/command_files.py +14 -128
- hpcflow/sdk/core/commands.py +35 -6
- hpcflow/sdk/core/element.py +122 -50
- hpcflow/sdk/core/errors.py +58 -2
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/loop.py +408 -50
- hpcflow/sdk/core/loop_cache.py +4 -4
- hpcflow/sdk/core/parameters.py +382 -37
- hpcflow/sdk/core/run_dir_files.py +13 -40
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +119 -30
- hpcflow/sdk/core/task_schema.py +68 -0
- hpcflow/sdk/core/test_utils.py +66 -27
- hpcflow/sdk/core/types.py +54 -1
- hpcflow/sdk/core/utils.py +136 -19
- hpcflow/sdk/core/workflow.py +1587 -356
- hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
- hpcflow/sdk/demo/cli.py +7 -0
- hpcflow/sdk/helper/cli.py +1 -0
- hpcflow/sdk/log.py +42 -15
- hpcflow/sdk/persistence/base.py +405 -53
- hpcflow/sdk/persistence/json.py +177 -52
- hpcflow/sdk/persistence/pending.py +237 -69
- hpcflow/sdk/persistence/store_resource.py +3 -2
- hpcflow/sdk/persistence/types.py +15 -4
- hpcflow/sdk/persistence/zarr.py +928 -81
- hpcflow/sdk/submission/jobscript.py +1408 -489
- hpcflow/sdk/submission/schedulers/__init__.py +40 -5
- hpcflow/sdk/submission/schedulers/direct.py +33 -19
- hpcflow/sdk/submission/schedulers/sge.py +51 -16
- hpcflow/sdk/submission/schedulers/slurm.py +44 -16
- hpcflow/sdk/submission/schedulers/utils.py +7 -2
- hpcflow/sdk/submission/shells/base.py +68 -20
- hpcflow/sdk/submission/shells/bash.py +222 -129
- hpcflow/sdk/submission/shells/powershell.py +200 -150
- hpcflow/sdk/submission/submission.py +852 -119
- hpcflow/sdk/submission/types.py +18 -21
- hpcflow/sdk/typing.py +24 -5
- hpcflow/sdk/utils/arrays.py +71 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +12 -0
- hpcflow/sdk/utils/strings.py +33 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +19 -0
- hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +821 -70
- hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
- hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
- hpcflow/tests/shells/wsl/test_wsl_submission.py +6 -0
- hpcflow/tests/unit/test_action.py +176 -0
- hpcflow/tests/unit/test_app.py +20 -0
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +133 -0
- hpcflow/tests/unit/test_config.py +122 -1
- hpcflow/tests/unit/test_element_iteration.py +47 -0
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_loop.py +1332 -27
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
- hpcflow/tests/unit/test_parameter.py +13 -0
- hpcflow/tests/unit/test_persistence.py +190 -8
- hpcflow/tests/unit/test_run.py +109 -3
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_shell.py +20 -0
- hpcflow/tests/unit/test_submission.py +5 -76
- hpcflow/tests/unit/test_workflow_template.py +31 -0
- hpcflow/tests/unit/utils/test_arrays.py +40 -0
- hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
- hpcflow/tests/unit/utils/test_hashing.py +65 -0
- hpcflow/tests/unit/utils/test_patches.py +5 -0
- hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
- hpcflow/tests/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +332 -0
- hpcflow/tests/workflows/test_run_status.py +198 -0
- hpcflow/tests/workflows/test_skip_downstream.py +696 -0
- hpcflow/tests/workflows/test_submission.py +140 -0
- hpcflow/tests/workflows/test_workflows.py +142 -2
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6587 -3
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/METADATA +7 -4
- hpcflow_new2-0.2.0a200.dist-info/RECORD +222 -0
- hpcflow_new2-0.2.0a190.dist-info/RECORD +0 -165
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/entry_points.txt +0 -0
@@ -4,11 +4,10 @@ Shell models based on Microsoft PowerShell.
|
|
4
4
|
|
5
5
|
from __future__ import annotations
|
6
6
|
import subprocess
|
7
|
-
from textwrap import dedent
|
7
|
+
from textwrap import dedent
|
8
8
|
from typing import TYPE_CHECKING
|
9
9
|
from typing_extensions import override
|
10
10
|
from hpcflow.sdk.typing import hydrate
|
11
|
-
from hpcflow.sdk.core import ABORT_EXIT_CODE
|
12
11
|
from hpcflow.sdk.submission.shells.base import Shell
|
13
12
|
from hpcflow.sdk.submission.shells.os_version import get_OS_info_windows
|
14
13
|
|
@@ -34,13 +33,13 @@ class WindowsPowerShell(Shell):
|
|
34
33
|
JS_ENV_SETUP_INDENT: ClassVar[str] = 2 * JS_INDENT
|
35
34
|
#: Template for the jobscript shebang line.
|
36
35
|
JS_SHEBANG: ClassVar[str] = ""
|
37
|
-
#: Template for the
|
38
|
-
|
36
|
+
#: Template for the jobscript functions file.
|
37
|
+
JS_FUNCS: ClassVar[str] = dedent(
|
39
38
|
"""\
|
40
39
|
function {workflow_app_alias} {{
|
41
40
|
& {{
|
42
41
|
{env_setup}{app_invoc} `
|
43
|
-
--with-config log_file_path "$
|
42
|
+
--with-config log_file_path "$env:{app_caps}_LOG_PATH" `
|
44
43
|
--config-dir "{config_dir}" `
|
45
44
|
--config-key "{config_invoc_key}" `
|
46
45
|
$args
|
@@ -50,6 +49,12 @@ class WindowsPowerShell(Shell):
|
|
50
49
|
function get_nth_line($file, $line) {{
|
51
50
|
Get-Content $file | Select-Object -Skip $line -First 1
|
52
51
|
}}
|
52
|
+
"""
|
53
|
+
)
|
54
|
+
#: Template for the common part of the jobscript header.
|
55
|
+
JS_HEADER: ClassVar[str] = dedent(
|
56
|
+
"""\
|
57
|
+
$ErrorActionPreference = 'Stop'
|
53
58
|
|
54
59
|
function JoinMultiPath {{
|
55
60
|
$numArgs = $args.Length
|
@@ -58,90 +63,141 @@ class WindowsPowerShell(Shell):
|
|
58
63
|
$path = Join-Path $path $args[$i]
|
59
64
|
}}
|
60
65
|
return $path
|
61
|
-
}}
|
62
|
-
|
63
|
-
function StartJobHere($block) {{
|
64
|
-
$jobInitBlock = [scriptblock]::Create(@"
|
65
|
-
Function wkflow_app {{ $function:wkflow_app }}
|
66
|
-
Function get_nth_line {{ $function:get_nth_line }}
|
67
|
-
Function JoinMultiPath {{ $function:JoinMultiPath }}
|
68
|
-
Set-Location '$pwd'
|
69
|
-
"@)
|
70
|
-
Start-Job -InitializationScript $jobInitBlock -Script $block
|
71
|
-
}}
|
66
|
+
}}
|
72
67
|
|
73
68
|
$WK_PATH = $(Get-Location)
|
74
69
|
$WK_PATH_ARG = $WK_PATH
|
75
70
|
$SUB_IDX = {sub_idx}
|
76
71
|
$JS_IDX = {js_idx}
|
77
|
-
|
78
|
-
$
|
72
|
+
|
73
|
+
$SUB_DIR = JoinMultiPath $WK_PATH artifacts submissions $SUB_IDX
|
74
|
+
$JS_FUNCS_PATH = JoinMultiPath $SUB_DIR {jobscript_functions_dir} {jobscript_functions_name}
|
75
|
+
. $JS_FUNCS_PATH
|
76
|
+
|
77
|
+
$EAR_ID_FILE = JoinMultiPath $SUB_DIR {run_IDs_file_dir} {run_IDs_file_name}
|
78
|
+
$SUB_TMP_DIR = Join-Path $SUB_DIR {tmp_dir_name}
|
79
|
+
$SUB_LOG_DIR = Join-Path $SUB_DIR {log_dir_name}
|
80
|
+
$SUB_STD_DIR = Join-Path $SUB_DIR {app_std_dir_name}
|
81
|
+
$SUB_SCRIPTS_DIR = Join-Path $SUB_DIR {scripts_dir_name}
|
82
|
+
|
83
|
+
$env:{app_caps}_WK_PATH = $WK_PATH
|
84
|
+
$env:{app_caps}_WK_PATH_ARG = $WK_PATH_ARG
|
85
|
+
$env:{app_caps}_SUB_IDX = {sub_idx}
|
86
|
+
$env:{app_caps}_SUB_SCRIPTS_DIR = $SUB_SCRIPTS_DIR
|
87
|
+
$env:{app_caps}_SUB_TMP_DIR = $SUB_TMP_DIR
|
88
|
+
$env:{app_caps}_SUB_LOG_DIR = $SUB_LOG_DIR
|
89
|
+
$env:{app_caps}_SUB_STD_DIR = $SUB_STD_DIR
|
90
|
+
$env:{app_caps}_LOG_PATH = Join-Path $SUB_LOG_DIR "js_$JS_IDX.log"
|
91
|
+
$env:{app_caps}_JS_FUNCS_PATH = $JS_FUNCS_PATH
|
92
|
+
$env:{app_caps}_JS_IDX = {js_idx}
|
93
|
+
$env:{app_caps}_RUN_ID_FILE = $EAR_ID_FILE
|
79
94
|
"""
|
80
95
|
)
|
81
96
|
#: Template for the jobscript header when directly executed.
|
82
97
|
JS_DIRECT_HEADER: ClassVar[str] = dedent(
|
83
98
|
"""\
|
84
99
|
{shebang}
|
85
|
-
|
86
100
|
{header}
|
87
101
|
{wait_command}
|
88
102
|
"""
|
89
103
|
)
|
90
|
-
#: Template for the
|
91
|
-
|
104
|
+
#: Template for enabling writing of the app log.
|
105
|
+
JS_RUN_LOG_PATH_ENABLE: ClassVar[str] = 'Join-Path $SUB_LOG_DIR "{run_log_file_name}"'
|
106
|
+
#: Template for disabling writing of the app log.
|
107
|
+
JS_RUN_LOG_PATH_DISABLE: ClassVar[str] = '" "'
|
108
|
+
#: Template for the run execution command.
|
109
|
+
JS_RUN_CMD: ClassVar[str] = (
|
110
|
+
"{workflow_app_alias} internal workflow $WK_PATH execute-run "
|
111
|
+
"$SUB_IDX $JS_IDX $block_idx $block_act_idx $EAR_ID\n"
|
112
|
+
)
|
113
|
+
#: Template for the execution command for multiple combined runs.
|
114
|
+
JS_RUN_CMD_COMBINED: ClassVar[str] = (
|
115
|
+
"{workflow_app_alias} internal workflow $WK_PATH execute-combined-runs "
|
116
|
+
"$SUB_IDX $JS_IDX\n"
|
117
|
+
)
|
118
|
+
#: Template for setting up run environment variables and executing the run.
|
119
|
+
JS_RUN: ClassVar[str] = dedent(
|
92
120
|
"""\
|
93
|
-
$
|
94
|
-
$
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
$EAR_ID = ($elem_EAR_IDs -split "{EAR_files_delimiter}")[$JS_act_idx]
|
99
|
-
if ($EAR_ID -eq -1) {{
|
100
|
-
continue
|
101
|
-
}}
|
102
|
-
|
103
|
-
$run_dir = ($elem_run_dirs -split "{EAR_files_delimiter}")[$JS_act_idx]
|
104
|
-
$run_dir_abs = "$WK_PATH\\$run_dir"
|
105
|
-
Set-Location $run_dir_abs
|
106
|
-
$app_stream_file = "$pwd/{run_stream_file}"
|
107
|
-
|
108
|
-
$skip = {workflow_app_alias} internal workflow $WK_PATH get-ear-skipped $EAR_ID 2>> $app_stream_file
|
109
|
-
$exc_sk = $LASTEXITCODE
|
110
|
-
|
111
|
-
if ($exc_sk -eq 0) {{
|
112
|
-
if ($skip -eq "1") {{
|
113
|
-
continue
|
114
|
-
}}
|
115
|
-
|
116
|
-
{workflow_app_alias} internal workflow $WK_PATH write-commands $SUB_IDX $JS_IDX $JS_act_idx $EAR_ID 2>&1 >> $app_stream_file
|
117
|
-
$exc_wc = $LASTEXITCODE
|
121
|
+
$EAR_ID = ($elem_EAR_IDs -split "{EAR_files_delimiter}")[$block_act_idx]
|
122
|
+
if ($EAR_ID -eq -1) {{
|
123
|
+
continue
|
124
|
+
}}
|
118
125
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
$exit_code = $LASTEXITCODE
|
125
|
-
}}
|
126
|
-
else {{
|
127
|
-
$exit_code = If ($exc_wc -ne 0) {{$exc_wc}} Else {{$exc_se}}
|
128
|
-
}}
|
129
|
-
}}
|
130
|
-
else {{
|
131
|
-
$exit_code = $exc_sk
|
132
|
-
}}
|
133
|
-
$global:LASTEXITCODE = $null
|
134
|
-
{workflow_app_alias} internal workflow $WK_PATH set-ear-end $JS_IDX $JS_act_idx $EAR_ID "--" "$exit_code" 2>&1 >> $app_stream_file
|
126
|
+
$env:{app_caps}_RUN_ID = $EAR_ID
|
127
|
+
$env:{app_caps}_RUN_LOG_PATH = {run_log_enable_disable}
|
128
|
+
$env:{app_caps}_LOG_PATH = $env:{app_caps}_RUN_LOG_PATH
|
129
|
+
$env:{app_caps}_RUN_STD_PATH = Join-Path $SUB_STD_DIR "$env:{app_caps}_RUN_ID.txt"
|
130
|
+
$env:{app_caps}_BLOCK_ACT_IDX = $block_act_idx
|
135
131
|
|
132
|
+
Set-Location $SUB_TMP_DIR
|
133
|
+
|
134
|
+
{run_cmd}
|
135
|
+
"""
|
136
|
+
)
|
137
|
+
#: Template for the action-run processing loop in a jobscript.
|
138
|
+
JS_ACT_MULTI: ClassVar[str] = dedent(
|
139
|
+
"""\
|
140
|
+
for ($block_act_idx = 0; $block_act_idx -lt {num_actions}; $block_act_idx += 1) {{
|
141
|
+
{run_block}
|
136
142
|
}}
|
143
|
+
"""
|
144
|
+
)
|
145
|
+
#: Template for the single-action-run execution in a jobscript.
|
146
|
+
JS_ACT_SINGLE: ClassVar[str] = dedent(
|
147
|
+
"""\
|
148
|
+
$block_act_idx = 0
|
149
|
+
{run_block}
|
150
|
+
"""
|
151
|
+
)
|
152
|
+
#: Template for setting up environment variables and running one or more action-runs.
|
153
|
+
JS_MAIN: ClassVar[str] = dedent(
|
154
|
+
"""\
|
155
|
+
$block_elem_idx = ($JS_elem_idx - {block_start_elem_idx})
|
156
|
+
$elem_EAR_IDs = get_nth_line $EAR_ID_FILE $JS_elem_idx
|
157
|
+
$env:{app_caps}_JS_ELEM_IDX = $JS_elem_idx
|
158
|
+
$env:{app_caps}_BLOCK_ELEM_IDX = $block_elem_idx
|
159
|
+
|
160
|
+
{action}
|
161
|
+
"""
|
162
|
+
)
|
163
|
+
#: Template for a jobscript-block header.
|
164
|
+
JS_BLOCK_HEADER: ClassVar[str] = dedent( # for single-block jobscripts only
|
165
|
+
"""\
|
166
|
+
$block_idx = 0
|
167
|
+
$env:{app_caps}_BLOCK_IDX = 0
|
168
|
+
"""
|
169
|
+
)
|
170
|
+
#: Template for single-element execution.
|
171
|
+
JS_ELEMENT_SINGLE: ClassVar[str] = dedent(
|
172
|
+
"""\
|
173
|
+
$JS_elem_idx = {block_start_elem_idx}
|
174
|
+
{main}
|
137
175
|
"""
|
138
176
|
)
|
139
177
|
#: Template for the element processing loop in a jobscript.
|
140
|
-
|
178
|
+
JS_ELEMENT_MULTI_LOOP: ClassVar[str] = dedent(
|
141
179
|
"""\
|
142
|
-
for ($JS_elem_idx =
|
180
|
+
for ($JS_elem_idx = {block_start_elem_idx}; $JS_elem_idx -lt ({block_start_elem_idx} + {num_elements}); $JS_elem_idx += 1) {{
|
143
181
|
{main}
|
144
182
|
}}
|
183
|
+
"""
|
184
|
+
)
|
185
|
+
#: Template for the jobscript block loop in a jobscript.
|
186
|
+
JS_BLOCK_LOOP: ClassVar[str] = dedent(
|
187
|
+
"""\
|
188
|
+
$num_elements = {num_elements}
|
189
|
+
$num_actions = {num_actions}
|
190
|
+
$block_start_elem_idx = 0
|
191
|
+
for ($block_idx = 0; $block_idx -lt {num_blocks}; $block_idx += 1 ) {{
|
192
|
+
$env:{app_caps}_BLOCK_IDX = $block_idx
|
193
|
+
{element_loop}
|
194
|
+
$block_start_elem_idx += $num_elements[$block_idx]
|
195
|
+
}}
|
196
|
+
"""
|
197
|
+
)
|
198
|
+
#: Template for the jobscript footer.
|
199
|
+
JS_FOOTER: ClassVar[str] = dedent(
|
200
|
+
"""\
|
145
201
|
Set-Location $WK_PATH
|
146
202
|
"""
|
147
203
|
)
|
@@ -150,6 +206,11 @@ class WindowsPowerShell(Shell):
|
|
150
206
|
"""Get the command for submitting a non-scheduled jobscript."""
|
151
207
|
return [*self.executable, "-File", js_path]
|
152
208
|
|
209
|
+
def get_command_file_launch_command(self, cmd_file_path: str) -> list[str]:
|
210
|
+
"""Get the command for launching the commands file for a given run."""
|
211
|
+
# note the "-File" argument is required for the correct exit code to be recorded.
|
212
|
+
return [*self.executable, "-File", cmd_file_path]
|
213
|
+
|
153
214
|
@override
|
154
215
|
def get_version_info(self, exclude_os: bool = False) -> VersionInfo:
|
155
216
|
"""Get powershell version information.
|
@@ -162,7 +223,7 @@ class WindowsPowerShell(Shell):
|
|
162
223
|
"""
|
163
224
|
|
164
225
|
proc = subprocess.run(
|
165
|
-
args=self.executable + ["$PSVersionTable.PSVersion.ToString()"],
|
226
|
+
args=self.executable + ["-Command", "$PSVersionTable.PSVersion.ToString()"],
|
166
227
|
stdout=subprocess.PIPE,
|
167
228
|
text=True,
|
168
229
|
)
|
@@ -186,6 +247,27 @@ class WindowsPowerShell(Shell):
|
|
186
247
|
app_invoc_exe = f"& '{app_invoc_exe}'"
|
187
248
|
return app_invoc_exe
|
188
249
|
|
250
|
+
@override
|
251
|
+
def format_env_var_get(self, var: str) -> str:
|
252
|
+
"""
|
253
|
+
Format retrieval of a shell environment variable.
|
254
|
+
"""
|
255
|
+
return f"$env:{var}"
|
256
|
+
|
257
|
+
@override
|
258
|
+
def format_array(self, lst: list) -> str:
|
259
|
+
"""
|
260
|
+
Format construction of a shell array.
|
261
|
+
"""
|
262
|
+
return "@(" + ", ".join(str(i) for i in lst) + ")"
|
263
|
+
|
264
|
+
@override
|
265
|
+
def format_array_get_item(self, arr_name: str, index: int | str) -> str:
|
266
|
+
"""
|
267
|
+
Format retrieval of a shell array item at a specified index.
|
268
|
+
"""
|
269
|
+
return f"${arr_name}[{index}]"
|
270
|
+
|
189
271
|
@override
|
190
272
|
def format_stream_assignment(self, shell_var_name: str, command: str) -> str:
|
191
273
|
"""
|
@@ -193,15 +275,63 @@ class WindowsPowerShell(Shell):
|
|
193
275
|
"""
|
194
276
|
return f"${shell_var_name} = {command}"
|
195
277
|
|
278
|
+
@override
|
279
|
+
def format_source_functions_file(self, app_name: str, commands: str) -> str:
|
280
|
+
"""
|
281
|
+
Format sourcing (i.e. invocation) of the jobscript functions file.
|
282
|
+
"""
|
283
|
+
app_caps = app_name.upper()
|
284
|
+
out = dedent(
|
285
|
+
"""\
|
286
|
+
. $env:{app_name}_JS_FUNCS_PATH
|
287
|
+
|
288
|
+
"""
|
289
|
+
).format(app_name=app_caps)
|
290
|
+
|
291
|
+
var_strings = (
|
292
|
+
f"{app_caps}_WK_PATH",
|
293
|
+
f"{app_caps}_SUB_SCRIPTS_DIR",
|
294
|
+
f"{app_caps}_JS_IDX",
|
295
|
+
f"{app_caps}_BLOCK_IDX",
|
296
|
+
f"{app_caps}_BLOCK_ACT_IDX",
|
297
|
+
f"{app_caps}_RUN_ID",
|
298
|
+
f"{app_caps}_RUN_STD_PATH",
|
299
|
+
f"{app_caps}_RUN_SCRIPT_NAME",
|
300
|
+
f"{app_caps}_RUN_SCRIPT_NAME_NO_EXT",
|
301
|
+
f"{app_caps}_RUN_SCRIPT_DIR",
|
302
|
+
f"{app_caps}_RUN_SCRIPT_PATH",
|
303
|
+
)
|
304
|
+
add = False
|
305
|
+
for i in var_strings:
|
306
|
+
if i in commands:
|
307
|
+
add = True
|
308
|
+
out += f"${i} = $env:{i}\n"
|
309
|
+
|
310
|
+
if add:
|
311
|
+
out += "\n"
|
312
|
+
|
313
|
+
return out
|
314
|
+
|
315
|
+
@override
|
316
|
+
def format_commands_file(self, app_name: str, commands: str) -> str:
|
317
|
+
"""
|
318
|
+
Format the commands file.
|
319
|
+
"""
|
320
|
+
return (
|
321
|
+
self.format_source_functions_file(app_name, commands)
|
322
|
+
+ commands
|
323
|
+
+ "\nexit $LASTEXITCODE\n"
|
324
|
+
)
|
325
|
+
|
196
326
|
@override
|
197
327
|
def format_save_parameter(
|
198
328
|
self,
|
199
329
|
workflow_app_alias: str,
|
200
330
|
param_name: str,
|
201
331
|
shell_var_name: str,
|
202
|
-
EAR_ID: int,
|
203
332
|
cmd_idx: int,
|
204
333
|
stderr: bool,
|
334
|
+
app_name: str,
|
205
335
|
) -> str:
|
206
336
|
"""
|
207
337
|
Produce code to save a parameter's value into the workflow persistent store.
|
@@ -209,90 +339,10 @@ class WindowsPowerShell(Shell):
|
|
209
339
|
# TODO: quote shell_var_name as well? e.g. if it's a white-space delimited list?
|
210
340
|
# and test.
|
211
341
|
stderr_str = " --stderr" if stderr else ""
|
342
|
+
app_caps = app_name.upper()
|
212
343
|
return (
|
213
|
-
f
|
214
|
-
f
|
215
|
-
f"{param_name} ${shell_var_name} {
|
216
|
-
f"2>&1 >> $app_stream_file"
|
217
|
-
f"\n"
|
218
|
-
)
|
219
|
-
|
220
|
-
@override
|
221
|
-
def format_loop_check(
|
222
|
-
self, workflow_app_alias: str, loop_name: str, run_ID: int
|
223
|
-
) -> str:
|
224
|
-
"""
|
225
|
-
Produce code to check the looping status of part of a workflow.
|
226
|
-
"""
|
227
|
-
return (
|
228
|
-
f"{workflow_app_alias} "
|
229
|
-
f"internal workflow $WK_PATH check-loop "
|
230
|
-
f"{loop_name} {run_ID} "
|
231
|
-
f"2>&1 >> $app_stream_file"
|
344
|
+
f'{workflow_app_alias} --std-stream "${app_caps}_RUN_STD_PATH" '
|
345
|
+
f'internal workflow "${app_caps}_WK_PATH" save-parameter {stderr_str}'
|
346
|
+
f'"--" {param_name} ${shell_var_name} ${app_caps}_RUN_ID {cmd_idx}'
|
232
347
|
f"\n"
|
233
348
|
)
|
234
|
-
|
235
|
-
@override
|
236
|
-
def wrap_in_subshell(self, commands: str, abortable: bool) -> str:
|
237
|
-
"""Format commands to run within a child scope.
|
238
|
-
|
239
|
-
This assumes `commands` ends in a newline.
|
240
|
-
|
241
|
-
"""
|
242
|
-
commands = indent(commands, self.JS_INDENT)
|
243
|
-
if abortable:
|
244
|
-
# run commands as a background job, and poll a file to check for abort
|
245
|
-
# requests:
|
246
|
-
return dedent(
|
247
|
-
"""\
|
248
|
-
$job = StartJobHere {{
|
249
|
-
$WK_PATH = $using:WK_PATH
|
250
|
-
$SUB_IDX = $using:SUB_IDX
|
251
|
-
$JS_IDX = $using:JS_IDX
|
252
|
-
$EAR_ID = $using:EAR_ID
|
253
|
-
$app_stream_file= $using:app_stream_file
|
254
|
-
|
255
|
-
{commands}
|
256
|
-
if ($LASTEXITCODE -ne 0) {{
|
257
|
-
throw
|
258
|
-
}}
|
259
|
-
}}
|
260
|
-
|
261
|
-
$is_abort = $null
|
262
|
-
$abort_file = JoinMultiPath $WK_PATH artifacts submissions $SUB_IDX abort_EARs.txt
|
263
|
-
while ($true) {{
|
264
|
-
$is_abort = get_nth_line $abort_file $EAR_ID
|
265
|
-
if ($job.State -ne "Running") {{
|
266
|
-
break
|
267
|
-
}}
|
268
|
-
elseif ($is_abort -eq "1") {{
|
269
|
-
Add-Content -Path $app_stream_file -Value "Abort instruction received; stopping commands..."
|
270
|
-
Stop-Job -Job $job
|
271
|
-
Wait-Job -Job $job
|
272
|
-
break
|
273
|
-
}}
|
274
|
-
else {{
|
275
|
-
Receive-Job -job $job | Write-Output
|
276
|
-
Start-Sleep 1 # TODO: TEMP: increase for production
|
277
|
-
}}
|
278
|
-
}}
|
279
|
-
Receive-Job -job $job | Write-Output
|
280
|
-
if ($job.state -eq "Completed") {{
|
281
|
-
exit 0
|
282
|
-
}}
|
283
|
-
elseif ($is_abort -eq "1") {{
|
284
|
-
exit {abort_exit_code}
|
285
|
-
}}
|
286
|
-
else {{
|
287
|
-
exit 1
|
288
|
-
}}
|
289
|
-
"""
|
290
|
-
).format(commands=commands, abort_exit_code=ABORT_EXIT_CODE)
|
291
|
-
else:
|
292
|
-
# run commands in "foreground":
|
293
|
-
return dedent(
|
294
|
-
"""\
|
295
|
-
& {{
|
296
|
-
{commands}}}
|
297
|
-
"""
|
298
|
-
).format(commands=commands)
|