From fd038c063a6b0ea07b42743686f0853670b44b8d Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 09:08:03 +0100 Subject: [PATCH 01/49] Add schema and validator for help manifest Introduces help.schema.json, the JSON Schema for a future manifest describing ecflow_client CLI help metadata. Command kind is restricted to task/user, option kind to global-option/command-option, and a command-option must name its single owning command. Adds validate_help_manifest.py, checking both schema conformance and cross-referential rules a schema alone cannot express: unique names per array, command-option -> command linkage, and symmetric pairs_with references between options. Wires the validator into the docs build as the ecflow_client_help_validate CMake target, a dependency of ecflow_client_docs, so an invalid manifest fails fast before Sphinx runs. Adds jsonschema to docs/requirements.txt accordingly. Adds help.json as a minimal, empty seed manifest that already validates; later changes will populate it with real content, moving CLI help off today's runtime-parsed --help text. --- docs/CMakeLists.txt | 24 +++- docs/client_api/help.json | 7 + docs/client_api/help.schema.json | 155 ++++++++++++++++++++++ docs/client_api/validate_help_manifest.py | 113 ++++++++++++++++ docs/requirements.txt | 1 + 5 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 docs/client_api/help.json create mode 100644 docs/client_api/help.schema.json create mode 100755 docs/client_api/validate_help_manifest.py diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index b7bd83af7..c27b9a3c1 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -22,6 +22,28 @@ else() ecbuild_fatal_error("Sphinx executable not present at ${SPHINX_EXECUTABLE}") endif() +# +# Validate the ecFlow CLI help manifest +# +# This is the single source of ecflow_client CLI help metadata, eventually consumed +# both by the C++ client (embedded at build time) and by this documentation build. +# Validation fails fast on an invalid manifest, before Sphinx or the (future) +# manifest-driven build.py consume it. +# + +add_custom_command( + OUTPUT validate_ecflow_client_help_manifest + COMMAND + ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/client_api/validate_help_manifest.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/client_api + USES_TERMINAL + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/help.json + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/help.schema.json + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/validate_help_manifest.py +) +add_custom_target(ecflow_client_help_validate DEPENDS validate_ecflow_client_help_manifest) + # # (Re-)generate ecFlow CLI documentation # @@ -54,7 +76,7 @@ add_custom_command( USES_TERMINAL DEPENDS ecflow_client ) -add_custom_target(ecflow_client_docs DEPENDS generate_ecflow_client_docs) +add_custom_target(ecflow_client_docs DEPENDS generate_ecflow_client_docs ecflow_client_help_validate) # diff --git a/docs/client_api/help.json b/docs/client_api/help.json new file mode 100644 index 000000000..d545c674e --- /dev/null +++ b/docs/client_api/help.json @@ -0,0 +1,7 @@ +{ + "schema_version": 1, + "topics": [], + "commands": [], + "options": [], + "environment_variables": [] +} diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json new file mode 100644 index 000000000..051733cdf --- /dev/null +++ b/docs/client_api/help.schema.json @@ -0,0 +1,155 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ecflow.readthedocs.io/schemas/help-manifest.json", + "title": "ecflow_client help manifest", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "topics", "commands", "options", "environment_variables"], + "properties": { + "schema_version": { + "type": "integer", + "minimum": 1 + }, + "topics": { + "type": "array", + "items": { "$ref": "#/$defs/topic" } + }, + "commands": { + "type": "array", + "items": { "$ref": "#/$defs/command" } + }, + "options": { + "type": "array", + "items": { "$ref": "#/$defs/option" } + }, + "environment_variables": { + "type": "array", + "items": { "$ref": "#/$defs/environment_variable" } + } + }, + "$defs": { + "description_block": { + "description": "A paragraph of prose, or a preformatted block reproduced verbatim (e.g. CtsCmd's ASCII-art tables).", + "oneOf": [ + { "type": "string", "minLength": 1 }, + { + "type": "object", + "additionalProperties": false, + "required": ["verbatim"], + "properties": { + "verbatim": { "type": "string", "minLength": 1 } + } + } + ] + }, + "description": { + "type": "array", + "items": { "$ref": "#/$defs/description_block" } + }, + "argument": { + "type": "object", + "additionalProperties": false, + "required": ["name", "optional", "description"], + "properties": { + "name": { "type": "string", "minLength": 1 }, + "optional": { "type": "boolean" }, + "description": { "type": "string", "minLength": 1 } + } + }, + "command": { + "type": "object", + "additionalProperties": false, + "required": ["name", "kind", "visibility", "implementation", "summary", "description", "usage"], + "properties": { + "name": { "type": "string", "minLength": 1 }, + "kind": { + "description": "Task and user are the only two command kinds; there is no third 'child' category.", + "enum": ["task", "user"] + }, + "visibility": { + "description": "public: usable standalone; group-only: usable only inside --group (e.g. why, show); internal: never registered in CtsCmdRegistry (e.g. MoveCmd).", + "enum": ["public", "group-only", "internal"] + }, + "implementation": { "type": "string", "minLength": 1 }, + "summary": { "type": "string", "minLength": 1 }, + "description": { "$ref": "#/$defs/description" }, + "arguments": { + "type": "array", + "items": { "$ref": "#/$defs/argument" } + }, + "usage": { + "type": "array", + "items": { "type": "string", "minLength": 1 }, + "minItems": 1 + } + } + }, + "option": { + "type": "object", + "additionalProperties": false, + "required": ["name", "kind", "summary", "description"], + "properties": { + "name": { "type": "string", "minLength": 1 }, + "kind": { + "description": "global-option: registered once, applies regardless of command; command-option: registered locally by one command.", + "enum": ["global-option", "command-option"] + }, + "command": { + "description": "Required, and only meaningful, when kind is command-option: names the single owning command.", + "type": "string", + "minLength": 1 + }, + "summary": { "type": "string", "minLength": 1 }, + "description": { "$ref": "#/$defs/description" }, + "requires": { + "description": "Build-feature flag gating this option, e.g. ECF_OPENSSL.", + "type": "string", + "minLength": 1 + }, + "pairs_with": { + "description": "Name of another option that must be supplied alongside this one; the reference must be symmetric.", + "type": "string", + "minLength": 1 + } + }, + "if": { + "properties": { "kind": { "const": "command-option" } } + }, + "then": { + "required": ["command"] + }, + "else": { + "not": { "required": ["command"] } + } + }, + "environment_variable": { + "type": "object", + "additionalProperties": false, + "required": ["name", "type", "required", "applies_to", "description"], + "properties": { + "name": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" }, + "type": { "enum": ["string", "int", "any"] }, + "required": { "enum": ["mandatory", "optional"] }, + "applies_to": { + "description": "both: every command; task: task commands only, in addition to the both entries.", + "enum": ["both", "task"] + }, + "requires": { + "description": "Build-feature flag gating this variable, e.g. ECF_OPENSSL.", + "type": "string", + "minLength": 1 + }, + "description": { "type": "string", "minLength": 1 } + } + }, + "topic": { + "type": "object", + "additionalProperties": false, + "required": ["name", "summary"], + "properties": { + "name": { "type": "string", "minLength": 1 }, + "summary": { "type": "string", "minLength": 1 } + } + } + } +} diff --git a/docs/client_api/validate_help_manifest.py b/docs/client_api/validate_help_manifest.py new file mode 100755 index 000000000..04ee5f1e9 --- /dev/null +++ b/docs/client_api/validate_help_manifest.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +"""Validate docs/client_api/help.json against docs/client_api/help.schema.json. + +Beyond JSON Schema conformance, this also checks the cross-referential rules that a +schema alone cannot express: pairs_with symmetry, command-option -> command +linkage, and name uniqueness within each array. +""" +import argparse +import json +import pathlib +import sys + +import jsonschema + + +def load_json(path: pathlib.Path): + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def check_schema(manifest, schema): + validator_cls = jsonschema.validators.validator_for(schema) + validator_cls.check_schema(schema) + validator = validator_cls(schema) + return sorted(validator.iter_errors(manifest), key=lambda error: list(map(str, error.path))) + + +def duplicates(values): + seen = set() + dupes = set() + for value in values: + if value in seen: + dupes.add(value) + seen.add(value) + return dupes + + +def check_cross_references(manifest): + problems = [] + + command_names = [command["name"] for command in manifest.get("commands", [])] + if dupes := duplicates(command_names): + problems.append(f"duplicate command name(s): {', '.join(sorted(dupes))}") + + option_names = [option["name"] for option in manifest.get("options", [])] + if dupes := duplicates(option_names): + problems.append(f"duplicate option name(s): {', '.join(sorted(dupes))}") + + env_var_names = [variable["name"] for variable in manifest.get("environment_variables", [])] + if dupes := duplicates(env_var_names): + problems.append(f"duplicate environment variable name(s): {', '.join(sorted(dupes))}") + + topic_names = [topic["name"] for topic in manifest.get("topics", [])] + if dupes := duplicates(topic_names): + problems.append(f"duplicate topic name(s): {', '.join(sorted(dupes))}") + + known_commands = set(command_names) + known_options = set(option_names) + pairs_with = {} + for option in manifest.get("options", []): + if option.get("kind") == "command-option": + owner = option.get("command") + if owner not in known_commands: + problems.append(f"option '{option['name']}' names unknown command '{owner}'") + if "pairs_with" in option: + pairs_with[option["name"]] = option["pairs_with"] + + for name, partner in pairs_with.items(): + if partner not in known_options: + problems.append(f"option '{name}' pairs_with unknown option '{partner}'") + elif pairs_with.get(partner) != name: + problems.append(f"option '{name}' pairs_with '{partner}', which does not pair back") + + return problems + + +def main(): + here = pathlib.Path(__file__).resolve().parent + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--manifest", type=pathlib.Path, default=here / "help.json") + parser.add_argument("--schema", type=pathlib.Path, default=here / "help.schema.json") + args = parser.parse_args() + + schema = load_json(args.schema) + manifest = load_json(args.manifest) + + schema_errors = check_schema(manifest, schema) + if schema_errors: + for error in schema_errors: + location = "/".join(str(part) for part in error.path) or "" + print(f"{args.manifest}: {location}: {error.message}", file=sys.stderr) + print(f"{len(schema_errors)} schema violation(s) found.", file=sys.stderr) + return 1 + + reference_problems = check_cross_references(manifest) + if reference_problems: + for problem in reference_problems: + print(f"{args.manifest}: {problem}", file=sys.stderr) + print(f"{len(reference_problems)} cross-reference problem(s) found.", file=sys.stderr) + return 1 + + print( + f"{args.manifest}: valid " + f"({len(manifest.get('commands', []))} commands, " + f"{len(manifest.get('options', []))} options, " + f"{len(manifest.get('environment_variables', []))} environment variables, " + f"{len(manifest.get('topics', []))} topics)" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/docs/requirements.txt b/docs/requirements.txt index 9edf44eab..f2dfdebcd 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -6,3 +6,4 @@ sphinx-rtd-theme>=3.0.0 sphinx-tabs>=3.4.0 sphinx-copybutton>=0.5.0 pyyaml>=6.0 +jsonschema>=4.18 From 43dedadf15033745dbd9292b5498b12f0d1a7d12 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 09:14:09 +0100 Subject: [PATCH 02/49] Add global options to help manifest Populates help.json's options array with the eleven global options (host, port, user, password, rid, ssl, http, https, help, version, debug), text taken verbatim from ClientOptions.cpp/CtsCmdRegistry.cpp and the checked-in RST pages. help and version are modeled with no environment-variable section, correcting Help.cpp's current misclassification of them as commands by elimination -- the reason they get one today. rid's description corrects "child commands" to "task commands", the one wording change the terminology fix permits; every other string is unchanged. --- docs/client_api/help.json | 96 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index d545c674e..07e913514 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -2,6 +2,100 @@ "schema_version": 1, "topics": [], "commands": [], - "options": [], + "options": [ + { + "name": "host", + "kind": "global-option", + "summary": "When specified overrides the environment variable ECF_HOST and default host: 'localhost'", + "description": [ + "When specified overrides the environment variable ECF_HOST and default host: 'localhost'" + ] + }, + { + "name": "port", + "kind": "global-option", + "summary": "When specified overrides the environment variable ECF_PORT and default port: '3141'", + "description": [ + "When specified overrides the environment variable ECF_PORT and default port: '3141'" + ] + }, + { + "name": "user", + "kind": "global-option", + "summary": "Specifies the user name used to contact the server. Must be used in combination with option --password.", + "description": [ + "Specifies the user name used to contact the server. Must be used in combination with option --password." + ], + "pairs_with": "password" + }, + { + "name": "password", + "kind": "global-option", + "summary": "Specifies the password used to contact the server. Must be used in combination with option --user.", + "description": [ + "Specifies the password used to contact the server. Must be used in combination with option --user." + ], + "pairs_with": "user" + }, + { + "name": "rid", + "kind": "global-option", + "summary": "When specified overrides the environment variable ECF_RID. Can only be used for task commands.", + "description": [ + "When specified overrides the environment variable ECF_RID. Can only be used for task commands." + ] + }, + { + "name": "ssl", + "kind": "global-option", + "requires": "ECF_OPENSSL", + "summary": "Enables the use of SSL when contacting the server.", + "description": [ + "Enables the use of SSL when contacting the server.", + "When specified overrides the environment variable ECF_SSL." + ] + }, + { + "name": "http", + "kind": "global-option", + "summary": "Enables communication over HTTP between client/server.", + "description": [ + "Enables communication over HTTP between client/server." + ] + }, + { + "name": "https", + "kind": "global-option", + "summary": "Enables communication over HTTPS between client/server.", + "description": [ + "Enables communication over HTTPS between client/server." + ] + }, + { + "name": "help", + "kind": "global-option", + "summary": "Produce help message", + "description": [ + "Produce help message" + ] + }, + { + "name": "version", + "kind": "global-option", + "summary": "Show ecflow client version number, and version of the boost library used", + "description": [ + "Show ecflow client version number, and version of the boost library used" + ] + }, + { + "name": "debug", + "kind": "global-option", + "summary": "Enables the display of client environment settings and execution details.", + "description": [ + "Enables the display of client environment settings and execution details.", + "Has the same effect as setting environment variable ECF_DEBUG_CLIENT." + ] + } + ], "environment_variables": [] } From e61b052b45e5e804d80269d2bd922af2c6791b88 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 09:16:04 +0100 Subject: [PATCH 03/49] Add topics to help manifest Populates help.json's topics array with the five keyword values --help= accepts: all, summary, task, user, option. Four are taken verbatim from Documentation::show_help()'s "Try:" banner (including the existing "user command" singular wording), with the child/task correction applied to the fourth. option has no banner text in the source -- it works via Documentation::show()'s dispatch but isn't advertised there -- so its summary is new text written to match the style of the other four. --- docs/client_api/help.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 07e913514..0c51157d4 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -1,6 +1,12 @@ { "schema_version": 1, - "topics": [], + "topics": [ + { "name": "all", "summary": "List all commands, verbosely" }, + { "name": "summary", "summary": "One line summary of all commands" }, + { "name": "task", "summary": "One line summary of task commands" }, + { "name": "user", "summary": "One line summary of user command" }, + { "name": "option", "summary": "One line summary of options" } + ], "commands": [], "options": [ { From 8413526e18bc4372aa0cfe2856242bed71fda3e6 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 09:26:45 +0100 Subject: [PATCH 04/49] Add environment variables to help manifest Populates help.json's environment_variables array with all twelve variables from Help.cpp's known_env_options, text taken verbatim. Extends help.schema.json with an overridable_by field, replacing the mandatory*/optional* asterisk convention: it names the global-option whose value can substitute for the variable, set only for ECF_HOST, ECF_PORT, and ECF_SSL, matching exactly which three carry an asterisk in the source today. ECF_RID has a real --rid override but is never marked as such in the source, so it correctly gets none. Adds a validator check confirming every overridable_by reference names a real global-option entry. --- docs/client_api/help.json | 91 ++++++++++++++++++++++- docs/client_api/help.schema.json | 5 ++ docs/client_api/validate_help_manifest.py | 10 +++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 0c51157d4..623f9012e 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -103,5 +103,94 @@ ] } ], - "environment_variables": [] + "environment_variables": [ + { + "name": "ECF_HOST", + "type": "string", + "required": "mandatory", + "applies_to": "both", + "overridable_by": "host", + "description": "The main server hostname; default value is 'localhost'" + }, + { + "name": "ECF_PORT", + "type": "int", + "required": "mandatory", + "applies_to": "both", + "overridable_by": "port", + "description": "The main server port; default value is '3141'" + }, + { + "name": "ECF_SSL", + "type": "any", + "required": "optional", + "applies_to": "both", + "requires": "ECF_OPENSSL", + "overridable_by": "ssl", + "description": "Enable secure communication between client and server." + }, + { + "name": "ECF_HOSTFILE", + "type": "string", + "required": "optional", + "applies_to": "both", + "description": "File that lists alternate hosts to try, if connection to main host fails" + }, + { + "name": "ECF_HOSTFILE_POLICY", + "type": "string", + "required": "optional", + "applies_to": "both", + "description": "The policy ('task' or 'all') to define which commands consider using alternate hosts." + }, + { + "name": "ECF_NAME", + "type": "string", + "required": "mandatory", + "applies_to": "task", + "description": "Full path name to the task" + }, + { + "name": "ECF_PASS", + "type": "string", + "required": "mandatory", + "applies_to": "task", + "description": "The job password (defined by the server, and used to authenticate client requests)" + }, + { + "name": "ECF_TRYNO", + "type": "int", + "required": "mandatory", + "applies_to": "task", + "description": "The run number of the job (defined by the server, and used in job/output file name generation." + }, + { + "name": "ECF_RID", + "type": "string", + "required": "mandatory", + "applies_to": "task", + "description": "The process identifier. Supports identifying zombies and automated killing of running jobs" + }, + { + "name": "ECF_TIMEOUT", + "type": "int", + "required": "optional", + "applies_to": "task", + "description": "Maximum time in *seconds* for client to deliver message to main server; default is 24 hours" + }, + { + "name": "ECF_DENIED", + "type": "any", + "required": "optional", + "applies_to": "task", + "description": "Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait." + }, + { + "name": "NO_ECF", + "type": "any", + "required": "optional", + "applies_to": "task", + "description": "If set, ecflow_client exits immediately with success; useful to test the scripts without a server" + } + ] } diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index 051733cdf..bd1790a7d 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -139,6 +139,11 @@ "type": "string", "minLength": 1 }, + "overridable_by": { + "description": "Name of the global-option whose value can substitute for this variable (e.g. ECF_HOST is overridable_by host). Today's Help.cpp marks exactly these as mandatory*/optional*; absence means no CLI override exists.", + "type": "string", + "minLength": 1 + }, "description": { "type": "string", "minLength": 1 } } }, diff --git a/docs/client_api/validate_help_manifest.py b/docs/client_api/validate_help_manifest.py index 04ee5f1e9..6b0fb20af 100755 --- a/docs/client_api/validate_help_manifest.py +++ b/docs/client_api/validate_help_manifest.py @@ -71,6 +71,16 @@ def check_cross_references(manifest): elif pairs_with.get(partner) != name: problems.append(f"option '{name}' pairs_with '{partner}', which does not pair back") + global_options = { + option["name"] for option in manifest.get("options", []) if option.get("kind") == "global-option" + } + for variable in manifest.get("environment_variables", []): + overridable_by = variable.get("overridable_by") + if overridable_by is not None and overridable_by not in global_options: + problems.append( + f"environment variable '{variable['name']}' overridable_by unknown global-option '{overridable_by}'" + ) + return problems From bfbc9f8fd4959c135279ef9a104a7860448da943 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 09:45:53 +0100 Subject: [PATCH 05/49] Add abort command entry to help manifest Populates help.json's commands array with abort, the first real command migrated (previous steps only covered options/topics/env vars). description holds only AbortCmd::desc()'s prose paragraphs, with the "child command" -> "task command" correction applied; the argN = .../Usage: text is deliberately omitted, to be synthesized at render time from arguments/usage instead, avoiding duplication between free text and structured data. Extends help.schema.json with a required type field on arguments, matching the source's "argN = (optional) type(name)" convention (e.g. string(reason)). Preserves abort's "reasonX" usage example as-is; this looks like a leftover typo for "reason" but is out of scope for byte-for-byte migration. --- docs/client_api/help.json | 23 ++++++++++++++++++++++- docs/client_api/help.schema.json | 6 +++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 623f9012e..ff09a849e 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -7,7 +7,28 @@ { "name": "user", "summary": "One line summary of user command" }, { "name": "option", "summary": "One line summary of options" } ], - "commands": [], + "commands": [ + { + "name": "abort", + "kind": "task", + "visibility": "public", + "implementation": "AbortCmd", + "summary": "Mark task as aborted. For use in the '.ecf' script file *only*", + "description": [ + "Mark task as aborted. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables", + "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT." + ], + "arguments": [ + { + "name": "reason", + "type": "string", + "optional": true, + "description": "Optionally provide a reason why the abort was raised" + } + ], + "usage": ["ecflow_client --abort=reasonX"] + } + ], "options": [ { "name": "host", diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index bd1790a7d..f09b99cea 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -49,9 +49,13 @@ "argument": { "type": "object", "additionalProperties": false, - "required": ["name", "optional", "description"], + "required": ["name", "type", "optional", "description"], "properties": { "name": { "type": "string", "minLength": 1 }, + "type": { + "description": "Matches the source's 'argN = (optional) type(name)' convention, e.g. string(reason).", + "enum": ["string", "int", "any"] + }, "optional": { "type": "boolean" }, "description": { "type": "string", "minLength": 1 } } From 85c2392bf06894207e3e30dcc85c7904801fc652 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 09:52:08 +0100 Subject: [PATCH 06/49] Add complete and init to help manifest Populates help.json's commands array with complete and init, text taken verbatim from CompleteCmd::desc()/InitCmd::desc(), with the "child command" -> "task command" correction applied to each. Confirms a pattern first seen as a question during init's own migration: both commands document a companion command-option via an argN(--flag)(optional) line rather than a true positional argument (init's add, complete's remove) -- modeled as a second arguments entry on each command, consistent with the earlier decision for init's add line. argN/Usage: text is omitted from description throughout, per the synthesis approach decided while migrating abort. --- docs/client_api/help.json | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index ff09a849e..998d3f162 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -27,6 +27,58 @@ } ], "usage": ["ecflow_client --abort=reasonX"] + }, + { + "name": "complete", + "kind": "task", + "visibility": "public", + "implementation": "CompleteCmd", + "summary": "Mark task as complete. For use in the '.ecf' script file *only*", + "description": [ + "Mark task as complete. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables", + "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.\nThe init command allows variables to be added, and complete command\nallows for them to be removed." + ], + "arguments": [ + { + "name": "remove", + "type": "any", + "optional": true, + "description": "a list of variables to removed from this task" + } + ], + "usage": [ + "ecflow_client --complete", + "ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" + ] + }, + { + "name": "init", + "kind": "task", + "visibility": "public", + "implementation": "InitCmd", + "summary": "Mark task as started(active). For use in the '.ecf' script file *only*", + "description": [ + "Mark task as started(active). For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables.", + "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT." + ], + "arguments": [ + { + "name": "process_or_remote_id", + "type": "string", + "optional": false, + "description": "The process id of the job or remote_id\nUsing remote id allows the jobs to be killed" + }, + { + "name": "add", + "type": "any", + "optional": true, + "description": "add/update variables as name value pairs" + } + ], + "usage": [ + "ecflow_client --init=$$", + "ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" + ] } ], "options": [ From 3bb8b2196400419a7749bf06a9793617707f9af6 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 10:06:25 +0100 Subject: [PATCH 07/49] Restore verbatim command descriptions Reverses the previous decision to synthesize argN = .../Usage: text at render time from structured arguments/usage. After comparing the actual formatting of siz commands shows the convention is inconsistent hand-written prose, not a reproducible template: type/name/description sit in different positions relative to =, some commands omit a type or a separate description line, and one uses a union type (string | int). Restores the full verbatim argN = .../Usage: text to abort's, complete's, and init's description arrays, and drops the placeholder type: "any" from complete's remove and init's add argument entries, since neither has a real type in the source. Loosens help.schema.json's argument definition accordingly: type becomes free text instead of a closed enum, and both type and description become optional, since the source does not always supply them. --- docs/client_api/help.json | 15 ++++++++------- docs/client_api/help.schema.json | 14 ++++++++++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 998d3f162..aada4f475 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -15,8 +15,9 @@ "implementation": "AbortCmd", "summary": "Mark task as aborted. For use in the '.ecf' script file *only*", "description": [ - "Mark task as aborted. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables", - "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT." + "Mark task as aborted. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1 = (optional) string(reason)\n Optionally provide a reason why the abort was raised", + "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.", + "Usage:\n ecflow_client --abort=reasonX" ], "arguments": [ { @@ -36,12 +37,12 @@ "summary": "Mark task as complete. For use in the '.ecf' script file *only*", "description": [ "Mark task as complete. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables", - "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.\nThe init command allows variables to be added, and complete command\nallows for them to be removed." + "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.\nThe init command allows variables to be added, and complete command\nallows for them to be removed.\n arg1(--remove)(optional) = a list of variables to removed from this task", + "Usage:\n ecflow_client --complete\n ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ], "arguments": [ { "name": "remove", - "type": "any", "optional": true, "description": "a list of variables to removed from this task" } @@ -58,8 +59,9 @@ "implementation": "InitCmd", "summary": "Mark task as started(active). For use in the '.ecf' script file *only*", "description": [ - "Mark task as started(active). For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables.", - "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT." + "Mark task as started(active). For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables.\n arg1(string) = process_or_remote_id The process id of the job or remote_id\n Using remote id allows the jobs to be killed\n arg2(--add)(optional)= add/update variables as name value pairs", + "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.", + "Usage:\n ecflow_client --init=$$\n ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ], "arguments": [ { @@ -70,7 +72,6 @@ }, { "name": "add", - "type": "any", "optional": true, "description": "add/update variables as name value pairs" } diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index f09b99cea..ad840c143 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -47,17 +47,23 @@ "items": { "$ref": "#/$defs/description_block" } }, "argument": { + "description": "Structured, best-effort metadata alongside the verbatim argN prose kept in the command's own description; the source's argN convention is inconsistent per-command (some omit type, some omit a separate description line, one uses a union type), so type and description are not always present, and type is free text rather than a closed set.", "type": "object", "additionalProperties": false, - "required": ["name", "type", "optional", "description"], + "required": ["name", "optional"], "properties": { "name": { "type": "string", "minLength": 1 }, "type": { - "description": "Matches the source's 'argN = (optional) type(name)' convention, e.g. string(reason).", - "enum": ["string", "int", "any"] + "description": "Free text matching whatever the source literally shows in parentheses, e.g. string, int, any, or a union such as 'string | int'. Absent when the source shows no type at all.", + "type": "string", + "minLength": 1 }, "optional": { "type": "boolean" }, - "description": { "type": "string", "minLength": 1 } + "description": { + "description": "Absent when the source gives no separate elaboration beyond the name/value itself.", + "type": "string", + "minLength": 1 + } } }, "command": { From f47367baaebfbc3d3a4b88ccac8297ce404996c7 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 10:09:26 +0100 Subject: [PATCH 08/49] Add event, label, and meter to help manifest Populates help.json's commands array with event, label, and meter, text taken verbatim from EventCmd::desc()/LabelCmd::desc()/ MeterCmd::desc(), with the "child command" -> "task command" correction applied to each. description holds the full original text, including each command's argN = ... and Usage: lines, per the verbatim-storage approach. arguments/usage are populated as best-effort structured metadata: event's arg1 uses a union type (string | int), and neither event's arg2 nor label's two arguments have a clean identifier name in the source, so the literal source phrase is used as name instead. --- docs/client_api/help.json | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index aada4f475..090ed87c6 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -52,6 +52,36 @@ "ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ] }, + { + "name": "event", + "kind": "task", + "visibility": "public", + "implementation": "EventCmd", + "summary": "Change event. For use in the '.ecf' script file *only*", + "description": [ + "Change event. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string | int) = event-name", + " arg2(string)(optional) = [ set | clear] default value is set", + "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", + "Usage:\n ecflow_client --event=ev # set the event, default since event initial value is clear\n ecflow_client --event=ev set # set the event, explicit\n ecflow_client --event=ev clear # clear the event, use when event initial value is set" + ], + "arguments": [ + { + "name": "event-name", + "type": "string | int", + "optional": false + }, + { + "name": "[ set | clear] default value is set", + "type": "string", + "optional": true + } + ], + "usage": [ + "ecflow_client --event=ev # set the event, default since event initial value is clear", + "ecflow_client --event=ev set # set the event, explicit", + "ecflow_client --event=ev clear # clear the event, use when event initial value is set" + ] + }, { "name": "init", "kind": "task", @@ -80,6 +110,55 @@ "ecflow_client --init=$$", "ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ] + }, + { + "name": "label", + "kind": "task", + "visibility": "public", + "implementation": "LabelCmd", + "summary": "Change Label. For use in the '.ecf' script file *only*", + "description": [ + "Change Label. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1 = label-name\n arg2 = The new label value\n The labels values can be single or multi-line(space separated quoted strings)", + "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", + "Usage:\n ecflow_client --label=progressed merlin" + ], + "arguments": [ + { + "name": "label-name", + "optional": false + }, + { + "name": "The new label value", + "optional": false, + "description": "The labels values can be single or multi-line(space separated quoted strings)" + } + ], + "usage": ["ecflow_client --label=progressed merlin"] + }, + { + "name": "meter", + "kind": "task", + "visibility": "public", + "implementation": "MeterCmd", + "summary": "Change meter. For use in the '.ecf' script file *only*", + "description": [ + "Change meter. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string) = meter-name\n arg2(int) = the new meter value", + "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", + "Usage:\n ecflow_client --meter=my_meter 20" + ], + "arguments": [ + { + "name": "meter-name", + "type": "string", + "optional": false + }, + { + "name": "the new meter value", + "type": "int", + "optional": false + } + ], + "usage": ["ecflow_client --meter=my_meter 20"] } ], "options": [ From 588c8b78ea8bd296a2b45dd49ce9baab15e00b78 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 10:19:19 +0100 Subject: [PATCH 09/49] Add queue and wait command to help manifest Populates help.json's commands array with queue and wait. Text was taken verbatim from QueueCmd::desc()/CtsWaitCmd::desc(), with the "child command" -> "task command" correction applied. queue's usage doesn't fit the short-invocation shape used by every other command's usage array -- desc() embeds a full shell script demonstrating a queue-draining loop -- so it is stored as a single verbatim block matching its description's Usage section exactly, rather than a paraphrased summary. --- docs/client_api/help.json | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 090ed87c6..2d507750c 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -159,6 +159,66 @@ } ], "usage": ["ecflow_client --meter=my_meter 20"] + }, + { + "name": "queue", + "kind": "task", + "visibility": "public", + "implementation": "QueueCmd", + "summary": "QueueCmd. For use in the '.ecf' script file *only*", + "description": [ + "QueueCmd. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string) = queue-name:\n arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ]\n active: returns the first queued/aborted step, the return string is the queue value from the definition\n no_of_aborted: returns number of aborted steps as a string, i.e 10\n reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors\n arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active)\n This is only valid for complete and aborted steps\n arg4(string) = path: (optional). The path where the queue is defined.\n By default we search for the queue up the node tree.", + "If this task command is a zombie, then the default action will be to *block*,\nThe default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will\nsearch for the queue up the node hierarchy. If no queue found, command fails", + "Usage:\nstep=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone", + "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" + ], + "arguments": [ + { + "name": "queue-name", + "type": "string", + "optional": false + }, + { + "name": "action", + "type": "string", + "optional": false, + "description": "[active | aborted | complete | no_of_aborted | reset ]\nactive: returns the first queued/aborted step, the return string is the queue value from the definition\nno_of_aborted: returns number of aborted steps as a string, i.e 10\nreset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors" + }, + { + "name": "step", + "type": "string", + "optional": false, + "description": "value returned from step=$(ecflow_client --queue=queue_name active)\nThis is only valid for complete and aborted steps" + }, + { + "name": "path", + "type": "string", + "optional": true, + "description": "(optional). The path where the queue is defined.\nBy default we search for the queue up the node tree." + } + ], + "usage": [ + "step=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone\n\ntrap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" + ] + }, + { + "name": "wait", + "kind": "task", + "visibility": "public", + "implementation": "CtsWaitCmd", + "summary": "Evaluates an expression, and block while the expression is false.", + "description": [ + "Evaluates an expression, and block while the expression is false.\nFor use in the '.ecf' file *only*, hence the context is supplied via environment variables\n arg1 = string(expression)", + "Usage:\n ecflow_client --wait=\"/suite/taskx == complete\"" + ], + "arguments": [ + { + "name": "expression", + "type": "string", + "optional": false + } + ], + "usage": ["ecflow_client --wait=\"/suite/taskx == complete\""] } ], "options": [ From 76928485f472213bad6eb41787cbc17baa884297 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 10:37:19 +0100 Subject: [PATCH 10/49] Embed the help manifest as a generated C++ header Adds cmake/GenerateClientHelp.cmake, which wraps docs/client_api/help.json in a header defining client_help_json as a std::string_view raw string literal, guarding against the delimiter appearing in the JSON. Wired into libs/CMakeLists.txt as a build-time add_custom_command rather than configure_file(), so the header regenerates on manifest changes without a full reconfigure -- verified with ninja alone. Uses ${ecflow_SOURCE_DIR}, not ${CMAKE_SOURCE_DIR}, which resolves to the wrapping project's root when built as a subproject. --- cmake/GenerateClientHelp.cmake | 65 ++++++++++++++++++++++++++++++++++ libs/CMakeLists.txt | 20 +++++++++++ 2 files changed, 85 insertions(+) create mode 100644 cmake/GenerateClientHelp.cmake diff --git a/cmake/GenerateClientHelp.cmake b/cmake/GenerateClientHelp.cmake new file mode 100644 index 000000000..cac9efe76 --- /dev/null +++ b/cmake/GenerateClientHelp.cmake @@ -0,0 +1,65 @@ +# Copyright 2009- ECMWF. +# +# This software is licensed under the terms of the Apache Licence version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. +# + +# +# Generates a C++ header embedding docs/client_api/help.json as a raw string +# literal, so ecflow_client can carry its own CLI help data without reading an +# external file at runtime. +# +# Invoked as a build-time custom command (not configure_file), so the header +# regenerates whenever the manifest changes, without requiring a full CMake +# reconfigure. +# +# Expected variables (passed via -D on the command line): +# MANIFEST path to docs/client_api/help.json +# OUTPUT path to the generated header to write +# + +if(NOT DEFINED MANIFEST) + message(FATAL_ERROR "GenerateClientHelp.cmake: MANIFEST is not set") +endif() +if(NOT DEFINED OUTPUT) + message(FATAL_ERROR "GenerateClientHelp.cmake: OUTPUT is not set") +endif() + +file(READ "${MANIFEST}" manifest_content) + +if(manifest_content MATCHES "\\)ecflow_help\"") + message(FATAL_ERROR + "GenerateClientHelp.cmake: ${MANIFEST} contains the raw-string delimiter " + ")ecflow_help\", which would break the generated header. Pick a different " + "delimiter here and in generated_client_help.hpp's consumers.") +endif() + +file(WRITE "${OUTPUT}" "/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +/* + * Generated from docs/client_api/help.json -- see cmake/GenerateClientHelp.cmake. + * + * DO NOT EDIT DIRECTLY. + */ + +#ifndef ecflow_client_generated_client_help_HPP +#define ecflow_client_generated_client_help_HPP + +#include + +inline constexpr std::string_view client_help_json = R\"ecflow_help( +${manifest_content})ecflow_help\"; + +#endif /* ecflow_client_generated_client_help_HPP */ +") diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 1c74fce37..985f08e8f 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -15,6 +15,25 @@ configure_file( core/src/ecflow/core/ecflow_source_build_dir.h.in ${CMAKE_BINARY_DIR}/generated/src/ecflow/core/ecflow_source_build_dir.h) +# +# Embed the CLI help manifest (docs/client_api/help.json) as a C++ header. +# +# A build-time custom command is used instead of configure_file(), so the +# header regenerates whenever the manifest changes, without requiring a full +# CMake reconfigure. +# +set(ecflow_client_help_manifest ${ecflow_SOURCE_DIR}/docs/client_api/help.json) +set(ecflow_client_help_generated_header + ${CMAKE_BINARY_DIR}/generated/src/ecflow/client/generated_client_help.hpp) +add_custom_command( + OUTPUT ${ecflow_client_help_generated_header} + COMMAND ${CMAKE_COMMAND} + -DMANIFEST=${ecflow_client_help_manifest} + -DOUTPUT=${ecflow_client_help_generated_header} + -P ${ecflow_SOURCE_DIR}/cmake/GenerateClientHelp.cmake + DEPENDS ${ecflow_client_help_manifest} ${ecflow_SOURCE_DIR}/cmake/GenerateClientHelp.cmake + COMMENT "Generating embedded CLI help manifest header from docs/client_api/help.json") + set(srcs # Attribute -- Headers attribute/src/ecflow/attribute/AutoArchiveAttr.hpp @@ -220,6 +239,7 @@ set(srcs base/src/ecflow/base/stc/ZombieGetCmd.cpp # Client -- Headers + ${ecflow_client_help_generated_header} client/src/ecflow/client/ClientCmdCache.hpp client/src/ecflow/client/ClientEnvironment.hpp client/src/ecflow/client/ClientInvoker.hpp From d34d161c648e7937a28b9331f831bc0d7050e3e9 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 10:53:54 +0100 Subject: [PATCH 11/49] Add HelpCatalog for lazy access to the help manifest Adds ecf::HelpCatalog, exposing manifest() as a lazily-parsed, cached nlohmann::json reference to the embedded help.json content. Parsing happens only on first use, since ecflow_client is invoked per task, potentially thousands of times per suite run, and only a small fraction of those invocations ever request help. Adds TestHelpCatalog.cpp, verifying the manifest parses, contains known entries, and is parsed once (same reference on repeated calls). --- libs/CMakeLists.txt | 2 + libs/client/CMakeLists.txt | 1 + libs/client/src/ecflow/client/HelpCatalog.cpp | 22 ++++++ libs/client/src/ecflow/client/HelpCatalog.hpp | 46 +++++++++++++ libs/client/test/TestHelpCatalog.cpp | 69 +++++++++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 libs/client/src/ecflow/client/HelpCatalog.cpp create mode 100644 libs/client/src/ecflow/client/HelpCatalog.hpp create mode 100644 libs/client/test/TestHelpCatalog.cpp diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 985f08e8f..53aaf1dbb 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -245,6 +245,7 @@ set(srcs client/src/ecflow/client/ClientInvoker.hpp client/src/ecflow/client/ClientOptions.hpp client/src/ecflow/client/Help.hpp + client/src/ecflow/client/HelpCatalog.hpp client/src/ecflow/client/HostsFile.hpp client/src/ecflow/client/Rtt.hpp client/src/ecflow/client/UrlCmd.hpp @@ -254,6 +255,7 @@ set(srcs client/src/ecflow/client/ClientEnvironment.cpp client/src/ecflow/client/ClientInvoker.cpp client/src/ecflow/client/Help.cpp + client/src/ecflow/client/HelpCatalog.cpp client/src/ecflow/client/HostsFile.cpp client/src/ecflow/client/Rtt.cpp client/src/ecflow/client/ClientOptions.cpp diff --git a/libs/client/CMakeLists.txt b/libs/client/CMakeLists.txt index 66a799a71..446e8ae58 100644 --- a/libs/client/CMakeLists.txt +++ b/libs/client/CMakeLists.txt @@ -58,6 +58,7 @@ set(test_srcs test/TestClientConfigurations.cpp test/TestClientEnvironment.cpp test/TestClientRetry.cpp + test/TestHelpCatalog.cpp test/TestHostsFile.cpp test/TestInitAddVariables.cpp test/TestLifeCycle.cpp diff --git a/libs/client/src/ecflow/client/HelpCatalog.cpp b/libs/client/src/ecflow/client/HelpCatalog.cpp new file mode 100644 index 000000000..9f2ceb492 --- /dev/null +++ b/libs/client/src/ecflow/client/HelpCatalog.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include "ecflow/client/HelpCatalog.hpp" + +#include "ecflow/client/generated_client_help.hpp" + +namespace ecf { + +const nlohmann::json& HelpCatalog::manifest() { + static const nlohmann::json instance = nlohmann::json::parse(client_help_json); + return instance; +} + +} // namespace ecf diff --git a/libs/client/src/ecflow/client/HelpCatalog.hpp b/libs/client/src/ecflow/client/HelpCatalog.hpp new file mode 100644 index 000000000..6a5efbe12 --- /dev/null +++ b/libs/client/src/ecflow/client/HelpCatalog.hpp @@ -0,0 +1,46 @@ +/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#ifndef ecflow_client_HelpCatalog_HPP +#define ecflow_client_HelpCatalog_HPP + +#include + +namespace ecf { + +/// +/// @brief Provides lazy, cached access to the embedded CLI help manifest. +/// +/// Allows access to the manifest (docs/client_api/help.json). +/// This is embedded at build time into `generated_client_help.hpp` and is parsed +/// only on first use and cached for the remaining lifetime of the process. +/// +/// The lazy nature of the load matters because ecflow_client is invoked by a task, +/// potentially thousands of times over a suite run; only a small fraction of those +/// invocations ever request help, and the rest must not pay a JSON-parsing cost. +/// +class HelpCatalog { +public: + HelpCatalog() = delete; + HelpCatalog(const HelpCatalog&) = delete; + HelpCatalog& operator=(const HelpCatalog&) = delete; + + /// + /// @brief Returns the parsed manifest, parsing it once on the first call. + /// + /// @return Reference to the manifest, valid for the remaining lifetime of the process. + /// @throws nlohmann::json::parse_error if the embedded manifest is malformed. + /// + static const nlohmann::json& manifest(); +}; + +} // namespace ecf + +#endif /* ecflow_client_HelpCatalog_HPP */ diff --git a/libs/client/test/TestHelpCatalog.cpp b/libs/client/test/TestHelpCatalog.cpp new file mode 100644 index 000000000..2ca4d5450 --- /dev/null +++ b/libs/client/test/TestHelpCatalog.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include + +#include "ecflow/client/HelpCatalog.hpp" +#include "ecflow/test/scaffold/Naming.hpp" + +/// +/// \brief Tests ecf::HelpCatalog's lazy access to the embedded CLI help manifest +/// + +BOOST_AUTO_TEST_SUITE(S_Client) + +BOOST_AUTO_TEST_SUITE(T_HelpCatalog) + +BOOST_AUTO_TEST_CASE(test_manifest_parses_and_has_expected_top_level_shape) { + ECF_NAME_THIS_TEST(); + + const nlohmann::json& manifest = ecf::HelpCatalog::manifest(); + + BOOST_REQUIRE(manifest.is_object()); + BOOST_CHECK_EQUAL(manifest.at("schema_version").get(), 1); + BOOST_CHECK(manifest.at("topics").is_array()); + BOOST_CHECK(manifest.at("commands").is_array()); + BOOST_CHECK(manifest.at("options").is_array()); + BOOST_CHECK(manifest.at("environment_variables").is_array()); +} + +BOOST_AUTO_TEST_CASE(test_manifest_contains_known_entries) { + ECF_NAME_THIS_TEST(); + + const nlohmann::json& manifest = ecf::HelpCatalog::manifest(); + + auto has_name = [](const nlohmann::json& array, const std::string& name) { + for (const auto& entry : array) { + if (entry.at("name") == name) { + return true; + } + } + return false; + }; + + BOOST_CHECK(has_name(manifest.at("commands"), "abort")); + BOOST_CHECK(has_name(manifest.at("options"), "host")); + BOOST_CHECK(has_name(manifest.at("environment_variables"), "ECF_HOST")); + BOOST_CHECK(has_name(manifest.at("topics"), "summary")); +} + +BOOST_AUTO_TEST_CASE(test_manifest_is_parsed_once_and_cached) { + ECF_NAME_THIS_TEST(); + + // Same reference on every call confirms the manifest is parsed lazily, + // once, and cached -- not re-parsed on every invocation. + const nlohmann::json& first = ecf::HelpCatalog::manifest(); + const nlohmann::json& second = ecf::HelpCatalog::manifest(); + BOOST_CHECK_EQUAL(&first, &second); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() From 636a312d72bcd2dcba2ff19b251eebb63c9ca51f Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 10:58:57 +0100 Subject: [PATCH 12/49] Add exact-lookup methods to HelpCatalog Adds find_command(), find_option(), and find_topic() to ecf::HelpCatalog, each returning const nlohmann::json* -- nullptr on a miss, matching the codebase's existing find_nothrow-style convention rather than throwing. Shares the scan logic via a private find_by_name() helper instead of repeating it three times. Adds six test cases (a hit and a miss per lookup) to TestHelpCatalog.cpp. --- libs/client/src/ecflow/client/HelpCatalog.cpp | 21 ++++++++++++ libs/client/src/ecflow/client/HelpCatalog.hpp | 32 +++++++++++++++++++ libs/client/test/TestHelpCatalog.cpp | 30 +++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/libs/client/src/ecflow/client/HelpCatalog.cpp b/libs/client/src/ecflow/client/HelpCatalog.cpp index 9f2ceb492..3329cbaab 100644 --- a/libs/client/src/ecflow/client/HelpCatalog.cpp +++ b/libs/client/src/ecflow/client/HelpCatalog.cpp @@ -19,4 +19,25 @@ const nlohmann::json& HelpCatalog::manifest() { return instance; } +const nlohmann::json* HelpCatalog::find_command(const std::string& name) { + return find_by_name(manifest().at("commands"), name); +} + +const nlohmann::json* HelpCatalog::find_option(const std::string& name) { + return find_by_name(manifest().at("options"), name); +} + +const nlohmann::json* HelpCatalog::find_topic(const std::string& name) { + return find_by_name(manifest().at("topics"), name); +} + +const nlohmann::json* HelpCatalog::find_by_name(const nlohmann::json& array, const std::string& name) { + for (const auto& entry : array) { + if (entry.at("name") == name) { + return &entry; + } + } + return nullptr; +} + } // namespace ecf diff --git a/libs/client/src/ecflow/client/HelpCatalog.hpp b/libs/client/src/ecflow/client/HelpCatalog.hpp index 6a5efbe12..2e68c04ab 100644 --- a/libs/client/src/ecflow/client/HelpCatalog.hpp +++ b/libs/client/src/ecflow/client/HelpCatalog.hpp @@ -11,6 +11,8 @@ #ifndef ecflow_client_HelpCatalog_HPP #define ecflow_client_HelpCatalog_HPP +#include + #include namespace ecf { @@ -39,6 +41,36 @@ class HelpCatalog { /// @throws nlohmann::json::parse_error if the embedded manifest is malformed. /// static const nlohmann::json& manifest(); + + /// + /// @brief Finds a command entry by exact name. + /// + /// @param name Exact command name to look up, e.g. "abort". + /// @return Pointer to the matching manifest entry, valid for the remaining lifetime + /// of the process, or nullptr if no command has this name. + /// + static const nlohmann::json* find_command(const std::string& name); + + /// + /// @brief Finds an option entry by exact name. + /// + /// @param name Exact option name to look up, e.g. "host". + /// @return Pointer to the matching manifest entry, valid for the remaining lifetime + /// of the process, or nullptr if no option has this name. + /// + static const nlohmann::json* find_option(const std::string& name); + + /// + /// @brief Finds a topic entry by exact name. + /// + /// @param name Exact topic name to look up, e.g. "summary". + /// @return Pointer to the matching manifest entry, valid for the remaining lifetime + /// of the process, or nullptr if no topic has this name. + /// + static const nlohmann::json* find_topic(const std::string& name); + +private: + static const nlohmann::json* find_by_name(const nlohmann::json& array, const std::string& name); }; } // namespace ecf diff --git a/libs/client/test/TestHelpCatalog.cpp b/libs/client/test/TestHelpCatalog.cpp index 2ca4d5450..cd7d0586d 100644 --- a/libs/client/test/TestHelpCatalog.cpp +++ b/libs/client/test/TestHelpCatalog.cpp @@ -64,6 +64,36 @@ BOOST_AUTO_TEST_CASE(test_manifest_is_parsed_once_and_cached) { BOOST_CHECK_EQUAL(&first, &second); } +BOOST_AUTO_TEST_CASE(test_find_command_by_exact_name) { + ECF_NAME_THIS_TEST(); + + const nlohmann::json* found = ecf::HelpCatalog::find_command("abort"); + BOOST_REQUIRE(found != nullptr); + BOOST_CHECK_EQUAL(found->at("implementation").get(), "AbortCmd"); + + BOOST_CHECK(ecf::HelpCatalog::find_command("no-such-command") == nullptr); +} + +BOOST_AUTO_TEST_CASE(test_find_option_by_exact_name) { + ECF_NAME_THIS_TEST(); + + const nlohmann::json* found = ecf::HelpCatalog::find_option("host"); + BOOST_REQUIRE(found != nullptr); + BOOST_CHECK_EQUAL(found->at("kind").get(), "global-option"); + + BOOST_CHECK(ecf::HelpCatalog::find_option("no-such-option") == nullptr); +} + +BOOST_AUTO_TEST_CASE(test_find_topic_by_exact_name) { + ECF_NAME_THIS_TEST(); + + const nlohmann::json* found = ecf::HelpCatalog::find_topic("summary"); + BOOST_REQUIRE(found != nullptr); + BOOST_CHECK(found->contains("summary")); + + BOOST_CHECK(ecf::HelpCatalog::find_topic("no-such-topic") == nullptr); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() From 8f878872add8b7a729cf9854bdbb5821fd43ae72 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 11:17:26 +0100 Subject: [PATCH 13/49] Route Help.cpp descriptions through the help manifest Documentation::show_summary() and show_command_help() now check HelpCatalog for a matching command/option and render its summary or description when present, falling back to the existing Boost-registered text for anything not yet migrated. This lets --help output for the 8 migrated commands and 11 migrated options come from the JSON manifest without disturbing any of the ~90 still-unmigrated entries. Also fixes six description-array bugs in help.json found while verifying manifest text against the original C++ source byte-for-byte: ssl/debug had a single paragraph incorrectly split across two array elements, and event/queue/http/https were each missing a trailing newline present in the source. --- docs/client_api/help.json | 14 ++--- libs/client/src/ecflow/client/Help.cpp | 79 +++++++++++++++++++++++--- 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 2d507750c..3531a8915 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -62,7 +62,7 @@ "Change event. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string | int) = event-name", " arg2(string)(optional) = [ set | clear] default value is set", "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", - "Usage:\n ecflow_client --event=ev # set the event, default since event initial value is clear\n ecflow_client --event=ev set # set the event, explicit\n ecflow_client --event=ev clear # clear the event, use when event initial value is set" + "Usage:\n ecflow_client --event=ev # set the event, default since event initial value is clear\n ecflow_client --event=ev set # set the event, explicit\n ecflow_client --event=ev clear # clear the event, use when event initial value is set\n" ], "arguments": [ { @@ -170,7 +170,7 @@ "QueueCmd. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string) = queue-name:\n arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ]\n active: returns the first queued/aborted step, the return string is the queue value from the definition\n no_of_aborted: returns number of aborted steps as a string, i.e 10\n reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors\n arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active)\n This is only valid for complete and aborted steps\n arg4(string) = path: (optional). The path where the queue is defined.\n By default we search for the queue up the node tree.", "If this task command is a zombie, then the default action will be to *block*,\nThe default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will\nsearch for the queue up the node hierarchy. If no queue found, command fails", "Usage:\nstep=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone", - "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" + "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }\n" ], "arguments": [ { @@ -270,8 +270,7 @@ "requires": "ECF_OPENSSL", "summary": "Enables the use of SSL when contacting the server.", "description": [ - "Enables the use of SSL when contacting the server.", - "When specified overrides the environment variable ECF_SSL." + "Enables the use of SSL when contacting the server.\nWhen specified overrides the environment variable ECF_SSL." ] }, { @@ -279,7 +278,7 @@ "kind": "global-option", "summary": "Enables communication over HTTP between client/server.", "description": [ - "Enables communication over HTTP between client/server." + "Enables communication over HTTP between client/server.\n" ] }, { @@ -287,7 +286,7 @@ "kind": "global-option", "summary": "Enables communication over HTTPS between client/server.", "description": [ - "Enables communication over HTTPS between client/server." + "Enables communication over HTTPS between client/server.\n" ] }, { @@ -311,8 +310,7 @@ "kind": "global-option", "summary": "Enables the display of client environment settings and execution details.", "description": [ - "Enables the display of client environment settings and execution details.", - "Has the same effect as setting environment variable ECF_DEBUG_CLIENT." + "Enables the display of client environment settings and execution details.\nHas the same effect as setting environment variable ECF_DEBUG_CLIENT." ] } ], diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index ffe38c058..8fe735f56 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -12,6 +12,7 @@ #include +#include "ecflow/client/HelpCatalog.hpp" #include "ecflow/core/Child.hpp" #include "ecflow/core/Ecf.hpp" #include "ecflow/core/Str.hpp" @@ -215,6 +216,53 @@ void sort_options_by_long_name(Help::descriptions_t& options) { options.begin(), options.end(), [](const auto& a, const auto& b) { return a->long_name() < b->long_name(); }); } +/// +/// @brief Finds the help manifest entry registered under the given name. +/// +/// Checks commands first, then options, since the two arrays are searched +/// with the same lookup key. +/// +/// @param[in] name Long name of the command or option to look up. +/// @return Pointer to the matching manifest entry, or nullptr if @p name is +/// not yet migrated onto the manifest, in which case the caller +/// falls back to the free-form Boost description registered for +/// that name. +/// +const nlohmann::json* catalog_entry_for(const std::string& name) { + if (const nlohmann::json* command = ecf::HelpCatalog::find_command(name)) { + return command; + } + return ecf::HelpCatalog::find_option(name); +} + +/// +/// @brief Joins a manifest entry's description blocks into a single string. +/// +/// Blocks are joined the same way the paragraphs were originally separated +/// in the C++ source: a blank line between blocks. A verbatim block (e.g. +/// CtsCmd's ASCII-art tables) is reproduced as-is, without a paragraph-break +/// interpretation of its own embedded newlines. +/// +/// @param[in] entry Manifest entry (command or option) holding a +/// "description" array of string or verbatim blocks. +/// @return The reconstructed description text. +/// +std::string catalog_description_text(const nlohmann::json& entry) { + std::string text; + for (const auto& block : entry.at("description")) { + if (!text.empty()) { + text += "\n\n"; + } + if (block.is_string()) { + text += block.get(); + } + else if (block.is_object() && block.contains("verbatim")) { + text += block.at("verbatim").get(); + } + } + return text; +} + class Documentation { public: using descriptions_t = boost::program_options::options_description; @@ -344,14 +392,24 @@ void Documentation::show_summary(std::ostream& os, PREDICATE select) const { int max_width = get_options_max_width(options); for (const auto& option : options) { - std::vector lines; - ecf::algorithm::split_at(lines, option->description(), "\n"); - if (!lines.empty()) { - std::string name = option->long_name(); - os << " " << std::left << std::setw(max_width) << name << " "; - os << Documentation::get_name_kind(name); - os << lines[0] << "\n"; + std::string name = option->long_name(); + + std::string first_line; + if (const nlohmann::json* entry = catalog_entry_for(name)) { + first_line = entry->at("summary").get(); + } + else { + std::vector lines; + ecf::algorithm::split_at(lines, option->description(), "\n"); + if (lines.empty()) { + continue; + } + first_line = lines[0]; } + + os << " " << std::left << std::setw(max_width) << name << " "; + os << Documentation::get_name_kind(name); + os << first_line << "\n"; } os << "\n"; } @@ -391,7 +449,12 @@ void Documentation::show_command_help(std::ostream& os, const std::string& comma os << "-"; } os << "\n\n"; - os << od->description() << "\n\n"; + if (const nlohmann::json* entry = catalog_entry_for(od->long_name())) { + os << catalog_description_text(*entry) << "\n\n"; + } + else { + os << od->description() << "\n\n"; + } if (!CommandFilter::is_option(od->long_name())) { os << client_env_description; if (ecf::Child::valid_child_cmd(od->long_name())) { From f7a2f039db33cf8ccec50dd410f52e8d169df04d Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 12:22:06 +0100 Subject: [PATCH 14/49] Move HelpCatalog into libs/base for command reuse Commands in base/ (task/user addOption(), CtsCmdRegistry) need to the header. Add summary_for()/description_for() returning std::optional, and switch Help.cpp to use them instead of its own duplicate helpers. --- cmake/GenerateClientHelp.cmake | 6 +- libs/CMakeLists.txt | 8 +-- libs/base/CMakeLists.txt | 1 + .../src/ecflow/base}/HelpCatalog.cpp | 39 ++++++++++++- .../src/ecflow/base}/HelpCatalog.hpp | 37 +++++++++++- .../{client => base}/test/TestHelpCatalog.cpp | 32 +++++++++- libs/client/CMakeLists.txt | 1 - libs/client/src/ecflow/client/Help.cpp | 58 ++----------------- 8 files changed, 115 insertions(+), 67 deletions(-) rename libs/{client/src/ecflow/client => base/src/ecflow/base}/HelpCatalog.cpp (52%) rename libs/{client/src/ecflow/client => base/src/ecflow/base}/HelpCatalog.hpp (62%) rename libs/{client => base}/test/TestHelpCatalog.cpp (71%) diff --git a/cmake/GenerateClientHelp.cmake b/cmake/GenerateClientHelp.cmake index cac9efe76..91ddb9244 100644 --- a/cmake/GenerateClientHelp.cmake +++ b/cmake/GenerateClientHelp.cmake @@ -53,13 +53,13 @@ file(WRITE "${OUTPUT}" "/* * DO NOT EDIT DIRECTLY. */ -#ifndef ecflow_client_generated_client_help_HPP -#define ecflow_client_generated_client_help_HPP +#ifndef ecflow_base_generated_client_help_HPP +#define ecflow_base_generated_client_help_HPP #include inline constexpr std::string_view client_help_json = R\"ecflow_help( ${manifest_content})ecflow_help\"; -#endif /* ecflow_client_generated_client_help_HPP */ +#endif /* ecflow_base_generated_client_help_HPP */ ") diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 53aaf1dbb..57bc4651e 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -24,7 +24,7 @@ configure_file( # set(ecflow_client_help_manifest ${ecflow_SOURCE_DIR}/docs/client_api/help.json) set(ecflow_client_help_generated_header - ${CMAKE_BINARY_DIR}/generated/src/ecflow/client/generated_client_help.hpp) + ${CMAKE_BINARY_DIR}/generated/src/ecflow/base/generated_client_help.hpp) add_custom_command( OUTPUT ${ecflow_client_help_generated_header} COMMAND ${CMAKE_COMMAND} @@ -85,7 +85,9 @@ set(srcs base/src/ecflow/base/ClientToServerRequest.hpp base/src/ecflow/base/Cmd.hpp base/src/ecflow/base/Connection.hpp + ${ecflow_client_help_generated_header} base/src/ecflow/base/Gnuplot.hpp + base/src/ecflow/base/HelpCatalog.hpp base/src/ecflow/base/HttpClient.hpp base/src/ecflow/base/Identification.hpp $<$:base/src/ecflow/base/Openssl.hpp> @@ -166,6 +168,7 @@ set(srcs base/src/ecflow/base/ClientToServerRequest.cpp base/src/ecflow/base/Connection.cpp base/src/ecflow/base/Gnuplot.cpp + base/src/ecflow/base/HelpCatalog.cpp base/src/ecflow/base/HttpClient.cpp base/src/ecflow/base/Identification.cpp base/src/ecflow/base/ServerReply.cpp @@ -239,13 +242,11 @@ set(srcs base/src/ecflow/base/stc/ZombieGetCmd.cpp # Client -- Headers - ${ecflow_client_help_generated_header} client/src/ecflow/client/ClientCmdCache.hpp client/src/ecflow/client/ClientEnvironment.hpp client/src/ecflow/client/ClientInvoker.hpp client/src/ecflow/client/ClientOptions.hpp client/src/ecflow/client/Help.hpp - client/src/ecflow/client/HelpCatalog.hpp client/src/ecflow/client/HostsFile.hpp client/src/ecflow/client/Rtt.hpp client/src/ecflow/client/UrlCmd.hpp @@ -255,7 +256,6 @@ set(srcs client/src/ecflow/client/ClientEnvironment.cpp client/src/ecflow/client/ClientInvoker.cpp client/src/ecflow/client/Help.cpp - client/src/ecflow/client/HelpCatalog.cpp client/src/ecflow/client/HostsFile.cpp client/src/ecflow/client/Rtt.cpp client/src/ecflow/client/ClientOptions.cpp diff --git a/libs/base/CMakeLists.txt b/libs/base/CMakeLists.txt index 2d44467b3..8e41781f3 100644 --- a/libs/base/CMakeLists.txt +++ b/libs/base/CMakeLists.txt @@ -21,6 +21,7 @@ set(test_srcs test/TestDeleteNodeCmd.cpp test/TestForceCmd.cpp test/TestFreeDepCmd.cpp + test/TestHelpCatalog.cpp test/TestInLimitAndLimit.cpp test/TestInLimitParsing.cpp test/TestLogCmd.cpp diff --git a/libs/client/src/ecflow/client/HelpCatalog.cpp b/libs/base/src/ecflow/base/HelpCatalog.cpp similarity index 52% rename from libs/client/src/ecflow/client/HelpCatalog.cpp rename to libs/base/src/ecflow/base/HelpCatalog.cpp index 3329cbaab..0ab539ff7 100644 --- a/libs/client/src/ecflow/client/HelpCatalog.cpp +++ b/libs/base/src/ecflow/base/HelpCatalog.cpp @@ -8,9 +8,9 @@ * nor does it submit to any jurisdiction. */ -#include "ecflow/client/HelpCatalog.hpp" +#include "ecflow/base/HelpCatalog.hpp" -#include "ecflow/client/generated_client_help.hpp" +#include "ecflow/base/generated_client_help.hpp" namespace ecf { @@ -31,6 +31,34 @@ const nlohmann::json* HelpCatalog::find_topic(const std::string& name) { return find_by_name(manifest().at("topics"), name); } +std::optional HelpCatalog::summary_for(const std::string& name) { + if (const nlohmann::json* entry = entry_for(name)) { + return entry->at("summary").get(); + } + return std::nullopt; +} + +std::optional HelpCatalog::description_for(const std::string& name) { + const nlohmann::json* entry = entry_for(name); + if (!entry) { + return std::nullopt; + } + + std::string text; + for (const auto& block : entry->at("description")) { + if (!text.empty()) { + text += "\n\n"; + } + if (block.is_string()) { + text += block.get(); + } + else if (block.is_object() && block.contains("verbatim")) { + text += block.at("verbatim").get(); + } + } + return text; +} + const nlohmann::json* HelpCatalog::find_by_name(const nlohmann::json& array, const std::string& name) { for (const auto& entry : array) { if (entry.at("name") == name) { @@ -40,4 +68,11 @@ const nlohmann::json* HelpCatalog::find_by_name(const nlohmann::json& array, con return nullptr; } +const nlohmann::json* HelpCatalog::entry_for(const std::string& name) { + if (const nlohmann::json* command = find_command(name)) { + return command; + } + return find_option(name); +} + } // namespace ecf diff --git a/libs/client/src/ecflow/client/HelpCatalog.hpp b/libs/base/src/ecflow/base/HelpCatalog.hpp similarity index 62% rename from libs/client/src/ecflow/client/HelpCatalog.hpp rename to libs/base/src/ecflow/base/HelpCatalog.hpp index 2e68c04ab..a5e07c80a 100644 --- a/libs/client/src/ecflow/client/HelpCatalog.hpp +++ b/libs/base/src/ecflow/base/HelpCatalog.hpp @@ -8,9 +8,10 @@ * nor does it submit to any jurisdiction. */ -#ifndef ecflow_client_HelpCatalog_HPP -#define ecflow_client_HelpCatalog_HPP +#ifndef ecflow_base_HelpCatalog_HPP +#define ecflow_base_HelpCatalog_HPP +#include #include #include @@ -69,10 +70,40 @@ class HelpCatalog { /// static const nlohmann::json* find_topic(const std::string& name); + /// + /// @brief Returns the one-line summary registered for a command or option. + /// + /// Checks commands first, then options, matching @ref find_command and + /// @ref find_option order. Returned by value so that callers never need to + /// see the underlying nlohmann::json representation. + /// + /// @param name Exact command or option name to look up, e.g. "abort". + /// @return The entry's "summary" field, or std::nullopt if @p name matches + /// neither a command nor an option in the manifest. + /// + static std::optional summary_for(const std::string& name); + + /// + /// @brief Returns the full description text registered for a command or option. + /// + /// Checks commands first, then options, matching @ref find_command and + /// @ref find_option order. The entry's "description" blocks are joined the + /// same way the paragraphs were originally separated in the C++ source: a + /// blank line between blocks. A verbatim block (e.g. CtsCmd's ASCII-art + /// tables) is reproduced as-is, without a paragraph-break interpretation of + /// its own embedded newlines. + /// + /// @param name Exact command or option name to look up, e.g. "abort". + /// @return The reconstructed description text, or std::nullopt if @p name + /// matches neither a command nor an option in the manifest. + /// + static std::optional description_for(const std::string& name); + private: static const nlohmann::json* find_by_name(const nlohmann::json& array, const std::string& name); + static const nlohmann::json* entry_for(const std::string& name); }; } // namespace ecf -#endif /* ecflow_client_HelpCatalog_HPP */ +#endif /* ecflow_base_HelpCatalog_HPP */ diff --git a/libs/client/test/TestHelpCatalog.cpp b/libs/base/test/TestHelpCatalog.cpp similarity index 71% rename from libs/client/test/TestHelpCatalog.cpp rename to libs/base/test/TestHelpCatalog.cpp index cd7d0586d..e630f89bd 100644 --- a/libs/client/test/TestHelpCatalog.cpp +++ b/libs/base/test/TestHelpCatalog.cpp @@ -10,14 +10,14 @@ #include -#include "ecflow/client/HelpCatalog.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/test/scaffold/Naming.hpp" /// /// \brief Tests ecf::HelpCatalog's lazy access to the embedded CLI help manifest /// -BOOST_AUTO_TEST_SUITE(S_Client) +BOOST_AUTO_TEST_SUITE(U_Base) BOOST_AUTO_TEST_SUITE(T_HelpCatalog) @@ -94,6 +94,34 @@ BOOST_AUTO_TEST_CASE(test_find_topic_by_exact_name) { BOOST_CHECK(ecf::HelpCatalog::find_topic("no-such-topic") == nullptr); } +BOOST_AUTO_TEST_CASE(test_summary_for_command_and_option) { + ECF_NAME_THIS_TEST(); + + std::optional command_summary = ecf::HelpCatalog::summary_for("abort"); + BOOST_REQUIRE(command_summary.has_value()); + BOOST_CHECK_EQUAL(*command_summary, ecf::HelpCatalog::find_command("abort")->at("summary").get()); + + std::optional option_summary = ecf::HelpCatalog::summary_for("host"); + BOOST_REQUIRE(option_summary.has_value()); + BOOST_CHECK_EQUAL(*option_summary, ecf::HelpCatalog::find_option("host")->at("summary").get()); + + BOOST_CHECK(!ecf::HelpCatalog::summary_for("no-such-name").has_value()); +} + +BOOST_AUTO_TEST_CASE(test_description_for_command_and_option) { + ECF_NAME_THIS_TEST(); + + std::optional command_description = ecf::HelpCatalog::description_for("abort"); + BOOST_REQUIRE(command_description.has_value()); + BOOST_CHECK(!command_description->empty()); + + std::optional option_description = ecf::HelpCatalog::description_for("host"); + BOOST_REQUIRE(option_description.has_value()); + BOOST_CHECK(!option_description->empty()); + + BOOST_CHECK(!ecf::HelpCatalog::description_for("no-such-name").has_value()); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/libs/client/CMakeLists.txt b/libs/client/CMakeLists.txt index 446e8ae58..66a799a71 100644 --- a/libs/client/CMakeLists.txt +++ b/libs/client/CMakeLists.txt @@ -58,7 +58,6 @@ set(test_srcs test/TestClientConfigurations.cpp test/TestClientEnvironment.cpp test/TestClientRetry.cpp - test/TestHelpCatalog.cpp test/TestHostsFile.cpp test/TestInitAddVariables.cpp test/TestLifeCycle.cpp diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 8fe735f56..38e847a7f 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -11,8 +11,9 @@ #include "ecflow/client/Help.hpp" #include +#include -#include "ecflow/client/HelpCatalog.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/core/Child.hpp" #include "ecflow/core/Ecf.hpp" #include "ecflow/core/Str.hpp" @@ -216,53 +217,6 @@ void sort_options_by_long_name(Help::descriptions_t& options) { options.begin(), options.end(), [](const auto& a, const auto& b) { return a->long_name() < b->long_name(); }); } -/// -/// @brief Finds the help manifest entry registered under the given name. -/// -/// Checks commands first, then options, since the two arrays are searched -/// with the same lookup key. -/// -/// @param[in] name Long name of the command or option to look up. -/// @return Pointer to the matching manifest entry, or nullptr if @p name is -/// not yet migrated onto the manifest, in which case the caller -/// falls back to the free-form Boost description registered for -/// that name. -/// -const nlohmann::json* catalog_entry_for(const std::string& name) { - if (const nlohmann::json* command = ecf::HelpCatalog::find_command(name)) { - return command; - } - return ecf::HelpCatalog::find_option(name); -} - -/// -/// @brief Joins a manifest entry's description blocks into a single string. -/// -/// Blocks are joined the same way the paragraphs were originally separated -/// in the C++ source: a blank line between blocks. A verbatim block (e.g. -/// CtsCmd's ASCII-art tables) is reproduced as-is, without a paragraph-break -/// interpretation of its own embedded newlines. -/// -/// @param[in] entry Manifest entry (command or option) holding a -/// "description" array of string or verbatim blocks. -/// @return The reconstructed description text. -/// -std::string catalog_description_text(const nlohmann::json& entry) { - std::string text; - for (const auto& block : entry.at("description")) { - if (!text.empty()) { - text += "\n\n"; - } - if (block.is_string()) { - text += block.get(); - } - else if (block.is_object() && block.contains("verbatim")) { - text += block.at("verbatim").get(); - } - } - return text; -} - class Documentation { public: using descriptions_t = boost::program_options::options_description; @@ -395,8 +349,8 @@ void Documentation::show_summary(std::ostream& os, PREDICATE select) const { std::string name = option->long_name(); std::string first_line; - if (const nlohmann::json* entry = catalog_entry_for(name)) { - first_line = entry->at("summary").get(); + if (std::optional summary = ecf::HelpCatalog::summary_for(name)) { + first_line = *summary; } else { std::vector lines; @@ -449,8 +403,8 @@ void Documentation::show_command_help(std::ostream& os, const std::string& comma os << "-"; } os << "\n\n"; - if (const nlohmann::json* entry = catalog_entry_for(od->long_name())) { - os << catalog_description_text(*entry) << "\n\n"; + if (std::optional text = ecf::HelpCatalog::description_for(od->long_name())) { + os << *text << "\n\n"; } else { os << od->description() << "\n\n"; From 659149fe96ba65b7608ec4fabaf9da6284770147 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 13:10:05 +0100 Subject: [PATCH 15/49] Add news/sync/sync_clock/sync_full to help manifest Migrates CSyncCmd's four actions (step 8.d), each registered as its own CLI option by a separate CSyncCmd instance in CtsCmdRegistry. Descriptions verified byte-for-byte against CSyncCmd.cpp's add_options() literals, and live --help output confirmed unchanged. Relax help.schema.json's usage field to optional: none of these four have "Usage:" text in their source, unlike every command migrated so far, so there is nothing verbatim to populate it with. --- docs/client_api/help.json | 40 ++++++++++++++++++++++++++++++++ docs/client_api/help.schema.json | 3 ++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 3531a8915..44518cadf 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -160,6 +160,16 @@ ], "usage": ["ecflow_client --meter=my_meter 20"] }, + { + "name": "news", + "kind": "user", + "visibility": "public", + "implementation": "CSyncCmd", + "summary": "Returns true if state of server definition changed.", + "description": [ + "Returns true if state of server definition changed.\n*Important* for use with c++/python interface only.\nRequires Given a client handle, change and modify number determine if server changed since last call\nThis relies on user calling sync after news to update the locally stored modify and change numbers.\nThese numbers are then used in the next call to news." + ] + }, { "name": "queue", "kind": "task", @@ -201,6 +211,36 @@ "step=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone\n\ntrap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" ] }, + { + "name": "sync", + "kind": "user", + "visibility": "public", + "implementation": "CSyncCmd", + "summary": "Incrementally synchronise the local definition with the one in the server.", + "description": [ + "Incrementally synchronise the local definition with the one in the server.\n*Important* for use with c++/python interface only.\nPreference should be given to this method as only the changes are returned.\nThis reduces the network bandwidth required to keep in sync with the server\nRequires a client handle, change and modify number, to get the incremental changes from server.\nThe change in server state is then and merged with the client definition." + ] + }, + { + "name": "sync_clock", + "kind": "user", + "visibility": "public", + "implementation": "CSyncCmd", + "summary": "Incrementally synchronise the local definition with the one in the server.", + "description": [ + "Incrementally synchronise the local definition with the one in the server.\n*Important* for use with c++/python interface only.\nSame as sync, but will *always* sync with suite clock if it has changed.\nPreference should be given to this method as only the changes are returned.\nThis reduces the network bandwidth required to keep in sync with the server\nRequires a client handle, change and modify number, to get the incremental changes from server.\nThe change in server state is then and merged with the client definition." + ] + }, + { + "name": "sync_full", + "kind": "user", + "visibility": "public", + "implementation": "CSyncCmd", + "summary": "Returns the full definition from the server.", + "description": [ + "Returns the full definition from the server.\n*Important* for use with c++/python interface only.\nRequires a client_handle. The returned definition is stored on the client." + ] + }, { "name": "wait", "kind": "task", diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index ad840c143..e36b675b0 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -69,7 +69,7 @@ "command": { "type": "object", "additionalProperties": false, - "required": ["name", "kind", "visibility", "implementation", "summary", "description", "usage"], + "required": ["name", "kind", "visibility", "implementation", "summary", "description"], "properties": { "name": { "type": "string", "minLength": 1 }, "kind": { @@ -88,6 +88,7 @@ "items": { "$ref": "#/$defs/argument" } }, "usage": { + "description": "Absent when the source has no documented invocation example (e.g. no 'Usage:' text in desc()).", "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1 From 177e8560755fee7e9135bb5ef1675a30c81c06c5 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 13:21:10 +0100 Subject: [PATCH 16/49] Add zombie_fob/fail/adopt/remove/block/kill to help manifest Migrates ZombieCmd's six actions, each registered as its own CLI option by the same ZombieCmd class dispatching on a ZombieCtrlAction enum value. --- docs/client_api/help.json | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 44518cadf..396639323 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -259,6 +259,66 @@ } ], "usage": ["ecflow_client --wait=\"/suite/taskx == complete\""] + }, + { + "name": "zombie_adopt", + "kind": "user", + "visibility": "public", + "implementation": "ZombieCmd", + "summary": "Locates the task in the servers list of zombies, and sets to adopt.", + "description": [ + "Locates the task in the servers list of zombies, and sets to adopt.\nNext time a child command (init,event,meter,label,abort,complete,wait queue) communicates with the server, the password on the zombie is adopted by the task.\nThis is only allowed if the process id matches, otherwise an error is issued.\nThe zombie reference stored in the server is then deleted.\n args = list of task paths, at least one expected\n --zombie_adopt=/path/to/task /path/to/task2" + ] + }, + { + "name": "zombie_block", + "kind": "user", + "visibility": "public", + "implementation": "ZombieCmd", + "summary": "Locates the task in the servers list of zombies, and sets flags to block it.", + "description": [ + "Locates the task in the servers list of zombies, and sets flags to block it.\nThis is default behaviour of the child commands(init,abort,complete,wait,queue)\nwhen the server cannot match the passwords. Each child commands will continue\nattempting to connect to the server for 24 hours, and will then return an error.\nThe connection timeout can be configured with environment ECF_TIMEOUT\n args = list of task paths, at least one expected\n --zombie_block=/path/to/task /path/to/task2" + ] + }, + { + "name": "zombie_fail", + "kind": "user", + "visibility": "public", + "implementation": "ZombieCmd", + "summary": "Locates the task in the servers list of zombies, and sets to fail.", + "description": [ + "Locates the task in the servers list of zombies, and sets to fail.\nNext time a child command (init,event,meter,label,abort,complete) which matches zombie, communicates with the server, will be set to fail.\nDepending on the job setup this may force a abort, the abort will also fail.\nHence job structure should use 'set -e' in the error trapping functions to prevent\ninfinite recursion.\nThe references to the zombie in the server is automatically deleted after 1 hour\n args = list of task paths, at least one expected\n --zombie_fail=/path/to/task /path/to/task2" + ] + }, + { + "name": "zombie_fob", + "kind": "user", + "visibility": "public", + "implementation": "ZombieCmd", + "summary": "Locates the task in the servers list of zombies, and sets to fob.", + "description": [ + "Locates the task in the servers list of zombies, and sets to fob.\nThis default behaviour of the child commands(label,event,meter) is to fob\nNext time the child commands (init,event,meter,label,abort,complete,wait,queue) communicate\nwith the server, they will complete successfully (but without updating the node tree)\nallowing the job to finish.\nThe references to the zombie in the server is automatically deleted after 1 hour\n args = list of task paths, at least one expected\n --zombie_fob=/path/to/task1 /path/to/task2" + ] + }, + { + "name": "zombie_kill", + "kind": "user", + "visibility": "public", + "implementation": "ZombieCmd", + "summary": "Locates the task in the servers list of zombies, and sets flags to kill", + "description": [ + "Locates the task in the servers list of zombies, and sets flags to kill\nThe kill is done using ECF_KILL_CMD, but using the process_id from the zombie\nThe job is allowed to continue until the kill is received\nCan only kill zombies that have an associated Task, hence path zombies\nmust be killed manually.\n arg = list of task paths, at least one expected\n --zombie_kill=/path/to/task /path/to/task2" + ] + }, + { + "name": "zombie_remove", + "kind": "user", + "visibility": "public", + "implementation": "ZombieCmd", + "summary": "Locates the task in the servers list of zombies, and removes it.", + "description": [ + "Locates the task in the servers list of zombies, and removes it.\nSince a job typically has many child commands (i.e init, complete, event, meter, label, wait, queue)\nthe zombie may reappear\n args = list of task paths, at least one expected\n --zombie_remove=/path/to/task /path/to/task2" + ] } ], "options": [ From be344afeae73af7c0caf7007f20c9ca58385a8e2 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 13:45:48 +0100 Subject: [PATCH 17/49] Add archive/check/edit_history/kill/resume/restore/status/suspend to help manifest Migrates PathsCmd's eight actions, each registered as its own CLI option by the same PathsCmd class dispatching on an Api enum value. archive and restore have multi-paragraph descriptions including an embedded suite/family configuration example; all descriptions verified byte-for-byte against PathsCmd.cpp's add_options() literals, and live --help output confirmed unchanged. --- docs/client_api/help.json | 86 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 396639323..412c79d6b 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -29,6 +29,29 @@ ], "usage": ["ecflow_client --abort=reasonX"] }, + { + "name": "archive", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Archives suite or family nodes *IF* they have child nodes(otherwise does nothing).", + "description": [ + "Archives suite or family nodes *IF* they have child nodes(otherwise does nothing).\nSaves the suite/family nodes to disk, and then removes the child nodes from the definition.\nThis saves memory in the server, when dealing with huge definitions that are not needed.\nIt improves time taken to checkpoint and reduces network bandwidth.\nIf the node is re-queued or begun, the child nodes are automatically restored.\nUse --restore to reload the archived nodes manually\nCare must be taken if you have trigger reference to the archived nodes\nThe nodes are saved to the file ECF_HOME/...check,\nwhere '/' has been replaced with ':' in ECF_NAME", + "Nodes like (family and suites) can also to automatically archived by using,\nthe 'autoarchive' attribute. The attribute is only applied once the node is complete", + "suite autoarchive\n family f1\n autoarchive +01:00 # archive one hour after complete\n task t1\n endfamily\n family f2\n autoarchive 01:00 # archive at 1 am in morning after complete\n task t1\n endfamily\n family f3\n autoarchive 10 # archive 10 days after complete\n task t1\n endfamily\n family f4\n autoarchive 0 # archive immediately (upto 60s) after complete\n task t1\n endfamily\nendsuite", + "Usage::\n --archive=/s1 # archive suite s1\n --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2\n --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" + ] + }, + { + "name": "check", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Checks the expression and limits in the server. Will also check trigger references.", + "description": [ + "Checks the expression and limits in the server. Will also check trigger references.\nTrigger expressions that reference paths that don't exist, will be reported as errors.\n(Note: On the client side unresolved paths in trigger expressions must\nhave an associated 'extern' specified)\n arg = [ _all_ | / | list of node paths ]\nUsage:\n --check=_all_ # Checks all the suites\n --check=/ # Checks all the suites\n --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" + ] + }, { "name": "complete", "kind": "task", @@ -52,6 +75,16 @@ "ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ] }, + { + "name": "edit_history", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Returns the edit history associated with a Node.", + "description": [ + "Returns the edit history associated with a Node.\nCan also be used to clear the edit history.\nUsage::\n --edit_history=/s1/f1/t1 # return history of changes for the given node\n --edit_history=clear # clear/purge *ALL* edit history from all nodes.\n" + ] + }, { "name": "event", "kind": "task", @@ -111,6 +144,16 @@ "ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ] }, + { + "name": "kill", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Kills the job associated with the node.", + "description": [ + "Kills the job associated with the node.\nIf a family or suite is selected, will kill hierarchically.\nKill uses the ECF_KILL_CMD variable. After variable substitution it is invoked as a command.\nThe command should be written in such a way that the output is written to %ECF_JOB%.kill\nas this allow the --file command to report the output: .e.e.\n /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::\nUsage::\n --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2\n --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1" + ] + }, { "name": "label", "kind": "task", @@ -211,6 +254,49 @@ "step=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone\n\ntrap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" ] }, + { + "name": "resume", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Resume the given node. This allows job generation for the given node, or any child node.", + "description": [ + "Resume the given node. This allows job generation for the given node, or any child node.\nUsage::\n --resume=/s1/f1/t1 # resume task s1/f1/t1\n --resume=/s1 /s2 # resume suites /s1 and /s2\n" + ] + }, + { + "name": "restore", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Manually restore archived nodes.", + "description": [ + "Manually restore archived nodes.\nRestore will fail if:\n - Node has not been archived\n - Node has children, (since archived nodes have no children)\n - If the file ECF_HOME/...check does not exist\nNodes can be restored manually(as in this command) but also automatically", + "Automatic restore is done using the 'autorestore' attribute.\nOnce the node containing the 'autorestore' completes, the attribute is applied", + " suite s\n family farchive_now\n autoarchive 0 # archive immediately after complete\n task tx\n endfamily\n family frestore_from_task\n task t1\n trigger ../farchive_nowarchived\n autorestore ../farchive_now # call autorestore when t1 completes\n endfamily\n endsuite", + "In this example task '/s/frestore_from_task/t1' is only triggered if 'farchive_now'\nis archived, then when t1 completes it will restore family 'farchive_now'\nUsage::\n --restore=/s1/f1 # restore family /s1/f1\n --restore=/s1 /s2 # restore suites /s1 and /s2" + ] + }, + { + "name": "status", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Shows the status of a job associated with a task, in %ECF_JOB%.stat file", + "description": [ + "Shows the status of a job associated with a task, in %ECF_JOB%.stat file\nIf a family or suite is selected, will invoke status command hierarchically.\nStatus uses the ECF_STATUS_CMD variable. After variable substitution it is invoked as a command.\nThe command should be written in such a way that the output is written to %ECF_JOB%.stat\nThis will allow the output of status command to be shown by the --file command\ni.e /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1::\nIf the process id cannot be found on the remote system, then the status command can also\narrange for the task to be aborted\nThe status command can fail for the following reasons:\n - ECF_STATUS_CMD not found\n - variable substitution fails\n - state is active but it can't find process id, i.e. ECF_RID\n - the status command does not exit cleanly\nWhen this happens a flag is set, STATUSCMD_FAILED, which is visible in the GUI\nUsage::\n --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat\n --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" + ] + }, + { + "name": "suspend", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Suspend the given node. This prevents job generation for the given node, or any child node.", + "description": [ + "Suspend the given node. This prevents job generation for the given node, or any child node.\nUsage::\n --suspend=/s1/f1/t1 # suspend task s1/f1/t1\n --suspend=/s1 /s2 # suspend suites /s1 and /s2\n" + ] + }, { "name": "sync", "kind": "user", From 5bc7fbae85ccb821f20c87a1f7bc34d89a1bc414 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 13:56:00 +0100 Subject: [PATCH 18/49] Add CtsCmd's eighteen actions to help manifest Migrates all eighteen CtsCmd actions (zombie_get, restore_from_checkpt, restart, shutdown, halt, terminate, reloadwsfile, reloadpasswdfile, reloadcustompasswdfile, force-dep-eval, ping, stats, stats_server, stats_reset, suites, debug_server_on, debug_server_off, server_load), each registered as its own CLI option by the same CtsCmd class dispatching on an Api enum value. Several of these embed pre-formatted content (a shared ASCII server- state table, and password/whitelist file format examples with blank lines of their own); all reproduce byte-for-byte as plain description array elements split at blank-line boundaries, with no need for the schema's verbatim block type. --- docs/client_api/help.json | 214 +++++++++++++++++++++++++++++++++++++- 1 file changed, 210 insertions(+), 4 deletions(-) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 412c79d6b..1e59d25a3 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -75,6 +75,22 @@ "ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ] }, + { + "name": "debug_server_off", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Disables debug output from the server", + "description": ["Disables debug output from the server"] + }, + { + "name": "debug_server_on", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Enables debug output from the server", + "description": ["Enables debug output from the server"] + }, { "name": "edit_history", "kind": "user", @@ -115,6 +131,24 @@ "ecflow_client --event=ev clear # clear the event, use when event initial value is set" ] }, + { + "name": "force-dep-eval", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Force dependency evaluation. Used for DEBUG only.", + "description": ["Force dependency evaluation. Used for DEBUG only."] + }, + { + "name": "halt", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Stop server communication with jobs, and new job scheduling.", + "description": [ + "Stop server communication with jobs, and new job scheduling.\nAlso stops automatic check pointing\n arg1 = yes(optional) # use to bypass confirmation prompt,i.e.\n --halt=yes\nThe following table shows server behaviour in the different states.\n|----------------------------------------------------------------------------------|\n| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n|--------------|--------------|--------------|---------------|---------------------|\n| RUNNING | yes | yes | yes | yes |\n| SHUTDOWN | yes | yes | no | yes |\n| HALTED | yes | no | no | no |\n|--------------|--------------|--------------|---------------|---------------------|" + ] + }, { "name": "init", "kind": "task", @@ -213,6 +247,16 @@ "Returns true if state of server definition changed.\n*Important* for use with c++/python interface only.\nRequires Given a client handle, change and modify number determine if server changed since last call\nThis relies on user calling sync after news to update the locally stored modify and change numbers.\nThese numbers are then used in the next call to news." ] }, + { + "name": "ping", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Check if server is running on given host/port. Result reported to standard output.", + "description": [ + "Check if server is running on given host/port. Result reported to standard output.\nUsage:\n --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144\n --ping --host=fred # Check if server alive on host fred and port ECF_PORT,\n # otherwise default port of 3141\n --ping # Check if server alive by using environment variables\n # ECF_HOST and ECF_PORT\nIf ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141" + ] + }, { "name": "queue", "kind": "task", @@ -255,13 +299,77 @@ ] }, { - "name": "resume", + "name": "reloadcustompasswdfile", "kind": "user", "visibility": "public", - "implementation": "PathsCmd", - "summary": "Resume the given node. This allows job generation for the given node, or any child node.", + "implementation": "CtsCmd", + "summary": "Reload the server custom password file.", + "description": [ + "Reload the server custom password file.", + "The custom password file (authentication) is used by the server to authenticate a 'user' by\nverifying if the password provided by the user matches the one held by the server. This\nparticular file is used for authentication of users that explicitly specify the user name\n(either via the environment variable ECF_USER or the --user option).", + "This mechanism should be used when most users use the machine login name, but a few users\nspecify their own user name, in which case the password must also be explicitly provided.", + "The file path is specified as the ECF_CUSTOM_PASSWD environment variable, both for the\nclient and server, and is loaded only by the server on *startup*. This means that the file\ncontents can be updated (i.e., add/remove users), but the file location cannot change during\nthe server execution.", + "The server automatically loads the password file content as part of the startup procedure.", + "The ECF_CUSTOM_PASSWD environment variable is used to specify the password file location,\nconsidering that\n - On the server the default file name is ..ecf.custom_passwd\n - On the client the default file name is ecf.custom_passwd", + "The format of the file is same for client and server:", + "\n4.5.0\n# comment\n # comment", + "The following is an example", + "4.5.0 # the version\nfred machine1 3142 xxyyyd\nfred machine2 3133 xxyyyd # comment\nbill machine2 3133 xxyggyyd", + "Notice that the same user may appear multiple times (associated with different host/port).\nThis allows the client to use the same password file to contact multiple servers.", + "For the password authentication to work, ensure the following:\n - The password is defined for the client and server\n - On the server, add at least the server administrator to the password file\n Note: If an empty password file (i.e., containing just the version) is used,\n no user is allowed access.\n - On the client, the password file should be readable only by the 'user' itself", + "Usage:\n --reloadcustompasswdfile" + ] + }, + { + "name": "reloadpasswdfile", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Reload the server password file.", + "description": [ + "Reload the server password file.", + "The password file (authentication) is used by the server to authenticate a 'user' by\nverifying if the password provided by the user matches the one held by the server.\nThe password file is also used on the client to automatically load the password for the\n'user' when connecting to the server.", + "When the server is configured to use a password file, then ALL users must have a password.", + "The file path is specified as the ECF_PASSWD environment variable, both for the client and\nserver, and is loaded only by the server on *startup*. This means that the file contents\ncan be updated (i.e., add/remove users), but the file location cannot change during the\nserver execution.", + "The server automatically loads the password file content as part of the startup procedure.", + "The ECF_PASSWD environment variable is used to specify the password file location,\nconsidering that\n - On the server, the default file name is ..ecf.passwd\n - On the client, the default file name is ecf.passwd", + "The format of the file is same for client and server:", + "\n4.5.0\n# comment\n # comment", + "The following is an example", + "4.5.0 # the version\nfred machine1 3142 xxyyyd\nfred machine2 3133 xxyyyd # comment\nbill machine2 3133 xxyggyyd", + "\nNotice that the same user may appear multiple times (associated with different host/port).\nThis allows the client to use the same password file to contact multiple servers.", + "For the password authentication to work, ensure the following:\n - The password is defined for the client and server\n - On the server, add at least the server administrator to the password file\n Note: If an empty password file (i.e., containing just the version) is used,\n no user is allowed access.\n - On the client, the password file should be readable only by the 'user' itself", + "Usage:\n --reloadpasswdfile" + ] + }, + { + "name": "reloadwsfile", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Reload the white list file.", + "description": [ + "Reload the white list file.", + "The white list file (authorisation) is used to verify if a 'user' is allowed to perform a\nspecific command.", + "The file path is specified as the ECF_LISTS variable, and loaded only once by the server\n(on *startup*). This means that the file contents can be updated, but the file location\ncannot change during the server execution.", + "The ECF_LISTS variable can be used as follows:\n - if ECF_LISTS is not specified, or if it is specified with value `ecf.lists`,\n then the server will use the value `..ecf.lists`\n - if ECF_LISTS is specified to be a path, such as /var/tmp/ecf.lists,\n then the server will use this path to reload the white list file", + "The server automatically loads the white list file content as part of the startup procedure,\nconsidering that if the file is not present or is empty (i.e., just contains the version\nnumber) then all users have read/write access.", + "The reload operation will fail if file does not exist or if the content is invalid.", + "Expected format for this file is:", + "\n# all characters after the first # in a line are considered comments and are discarded\n# empty lines are also discarded", + "4.4.14 # the version number is mandatory, even if no users are specified\n# Users with read/write access\nuser1\nuser2 # comment\n* # use this form if you want all users to have read/write access", + "# Users with read access, must have - before user name\n-user3 # comment\n-user4\n-* # use this form if you want all users to have read access", + "\nUsage:\n --reloadwsfile" + ] + }, + { + "name": "restart", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Start job scheduling, communication with jobs, and respond to all requests.", "description": [ - "Resume the given node. This allows job generation for the given node, or any child node.\nUsage::\n --resume=/s1/f1/t1 # resume task s1/f1/t1\n --resume=/s1 /s2 # resume suites /s1 and /s2\n" + "Start job scheduling, communication with jobs, and respond to all requests.\nThe following table shows server behaviour in the different states.\n|----------------------------------------------------------------------------------|\n| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n|--------------|--------------|--------------|---------------|---------------------|\n| RUNNING | yes | yes | yes | yes |\n| SHUTDOWN | yes | yes | no | yes |\n| HALTED | yes | no | no | no |\n|--------------|--------------|--------------|---------------|---------------------|" ] }, { @@ -277,6 +385,76 @@ "In this example task '/s/frestore_from_task/t1' is only triggered if 'farchive_now'\nis archived, then when t1 completes it will restore family 'farchive_now'\nUsage::\n --restore=/s1/f1 # restore family /s1/f1\n --restore=/s1 /s2 # restore suites /s1 and /s2" ] }, + { + "name": "restore_from_checkpt", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Ask the server to load the definition from an check pt file.", + "description": [ + "Ask the server to load the definition from an check pt file.\nThe server must be halted and the definition in the server must be deleted\nfirst, otherwise an error is returned" + ] + }, + { + "name": "resume", + "kind": "user", + "visibility": "public", + "implementation": "PathsCmd", + "summary": "Resume the given node. This allows job generation for the given node, or any child node.", + "description": [ + "Resume the given node. This allows job generation for the given node, or any child node.\nUsage::\n --resume=/s1/f1/t1 # resume task s1/f1/t1\n --resume=/s1 /s2 # resume suites /s1 and /s2\n" + ] + }, + { + "name": "server_load", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Generates gnuplot files that show the server load graphically.", + "description": [ + "Generates gnuplot files that show the server load graphically.\nThis is done by parsing the log file. If no log file is provided,\nthen the log file path is obtained from the server. If the returned\nlog file path is not accessible an error is returned\nThis command produces a three files in the CWD.\n o ..gnuplot.dat\n o ..gnuplot.script\n o ..png", + "The generated script can be manually changed, to see different rendering\neffects. i.e. just run 'gnuplot ..gnuplot.script'", + " arg1 = path to log file", + "If the path to log file is known, it is *preferable* to use this,\nrather than requesting the log path from the server.", + "Usage:\n --server_load=/path/to_log_file # Parses log and generate gnuplot files\n --server_load # Log file path is requested from server\n # which is then used to generate gnuplot files\n # *AVOID* if log file path is accessible", + "Now use any png viewer to see the output i.e", + "> display ..png\n> feh ..png\n> eog ..png\n> xdg-open ..png\n> w3m ..png\n" + ] + }, + { + "name": "shutdown", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Stop server from scheduling new jobs.", + "description": [ + "Stop server from scheduling new jobs.\n arg1 = yes(optional) # use to bypass confirmation prompt,i.e\n --shutdown=yes\nThe following table shows server behaviour in the different states.\n|----------------------------------------------------------------------------------|\n| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n|--------------|--------------|--------------|---------------|---------------------|\n| RUNNING | yes | yes | yes | yes |\n| SHUTDOWN | yes | yes | no | yes |\n| HALTED | yes | no | no | no |\n|--------------|--------------|--------------|---------------|---------------------|" + ] + }, + { + "name": "stats", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Returns the server statistics as a string.", + "description": ["Returns the server statistics as a string."] + }, + { + "name": "stats_reset", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Resets the server statistics.", + "description": ["Resets the server statistics."] + }, + { + "name": "stats_server", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Returns the server statistics as a struct and string. For test use only.", + "description": ["Returns the server statistics as a struct and string. For test use only."] + }, { "name": "status", "kind": "user", @@ -287,6 +465,14 @@ "Shows the status of a job associated with a task, in %ECF_JOB%.stat file\nIf a family or suite is selected, will invoke status command hierarchically.\nStatus uses the ECF_STATUS_CMD variable. After variable substitution it is invoked as a command.\nThe command should be written in such a way that the output is written to %ECF_JOB%.stat\nThis will allow the output of status command to be shown by the --file command\ni.e /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1::\nIf the process id cannot be found on the remote system, then the status command can also\narrange for the task to be aborted\nThe status command can fail for the following reasons:\n - ECF_STATUS_CMD not found\n - variable substitution fails\n - state is active but it can't find process id, i.e. ECF_RID\n - the status command does not exit cleanly\nWhen this happens a flag is set, STATUSCMD_FAILED, which is visible in the GUI\nUsage::\n --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat\n --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" ] }, + { + "name": "suites", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Returns the list of suites, in the order defined in the server.", + "description": ["Returns the list of suites, in the order defined in the server."] + }, { "name": "suspend", "kind": "user", @@ -327,6 +513,16 @@ "Returns the full definition from the server.\n*Important* for use with c++/python interface only.\nRequires a client_handle. The returned definition is stored on the client." ] }, + { + "name": "terminate", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Terminate the server.", + "description": [ + "Terminate the server.\n arg1 = yes(optional) # use to bypass confirmation prompt.i.e\n --terminate=yes" + ] + }, { "name": "wait", "kind": "task", @@ -346,6 +542,16 @@ ], "usage": ["ecflow_client --wait=\"/suite/taskx == complete\""] }, + { + "name": "zombie_get", + "kind": "user", + "visibility": "public", + "implementation": "CtsCmd", + "summary": "Returns the list of zombies from the server.", + "description": [ + "Returns the list of zombies from the server.\nResults reported to standard output." + ] + }, { "name": "zombie_adopt", "kind": "user", From e1ac96212e3b944238b3c59585261f9cd9720197 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 14:01:06 +0100 Subject: [PATCH 19/49] Add get/get_state/migrate/job_gen/checkJobGenOnly to help manifest Migrates five of CtsNodeCmd's six actions, each registered as its own CLI option by the same CtsNodeCmd class dispatching on an Api enum value. The sixth action, why, is group-only and stays out of scope here. migrate's description includes a small feature-comparison table against get/get_state; reproduces byte-for-byte as plain description array elements, same as CtsCmd's tables. --- docs/client_api/help.json | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 1e59d25a3..a5af61f7c 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -52,6 +52,16 @@ "Checks the expression and limits in the server. Will also check trigger references.\nTrigger expressions that reference paths that don't exist, will be reported as errors.\n(Note: On the client side unresolved paths in trigger expressions must\nhave an associated 'extern' specified)\n arg = [ _all_ | / | list of node paths ]\nUsage:\n --check=_all_ # Checks all the suites\n --check=/ # Checks all the suites\n --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" ] }, + { + "name": "checkJobGenOnly", + "kind": "user", + "visibility": "public", + "implementation": "CtsNodeCmd", + "summary": "Test hierarchical Job generation only, for chosen Node.", + "description": [ + "Test hierarchical Job generation only, for chosen Node.\nThe jobs are generated independent of the dependencies\nThis will generate the jobs *only*, i.e. no job submission. Used for checking job generation only\n arg = node path | arg = NULL\n If no node path specified generates for all Tasks in the definition. For Test only" + ] + }, { "name": "complete", "kind": "task", @@ -139,6 +149,26 @@ "summary": "Force dependency evaluation. Used for DEBUG only.", "description": ["Force dependency evaluation. Used for DEBUG only."] }, + { + "name": "get", + "kind": "user", + "visibility": "public", + "implementation": "CtsNodeCmd", + "summary": "Get the suite definition or node tree in form that is re-parse able", + "description": [ + "Get the suite definition or node tree in form that is re-parse able\nGet all suite node tree's from the server and write to standard out.\nThe output is parse-able, and can be used to re-load the definition\n arg = NULL | arg = node path\nUsage:\n --get # gets the definition from the server,and writes to standard out\n --get=/s1 # gets the suite from the server,and writes to standard out" + ] + }, + { + "name": "get_state", + "kind": "user", + "visibility": "public", + "implementation": "CtsNodeCmd", + "summary": "Get state data. For the whole suite definition or individual nodes.", + "description": [ + "Get state data. For the whole suite definition or individual nodes.\nThis will include event, meter, node state, trigger and time state.\nThe output is written to standard out.\n arg = NULL | arg = node path\nUsage:\n --get_state # gets the definition from the server,and writes to standard out\n --get_state=/s1 # gets the suite from the server,and writes to standard out" + ] + }, { "name": "halt", "kind": "user", @@ -178,6 +208,16 @@ "ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ] }, + { + "name": "job_gen", + "kind": "user", + "visibility": "public", + "implementation": "CtsNodeCmd", + "summary": "Job submission for chosen Node *based* on dependencies.", + "description": [ + "Job submission for chosen Node *based* on dependencies.\nThe server traverses the node tree every 60 seconds, and if the dependencies are free\ndoes job generation and submission. Sometimes the user may free time/date dependencies\nto avoid waiting for the server poll, this commands allows early job generation\n arg = node path | arg = NULL\n If no node path specified generates for full definition." + ] + }, { "name": "kill", "kind": "user", @@ -237,6 +277,18 @@ ], "usage": ["ecflow_client --meter=my_meter 20"] }, + { + "name": "migrate", + "kind": "user", + "visibility": "public", + "implementation": "CtsNodeCmd", + "summary": "Used to print state of the definition returned from the server to standard output.", + "description": [ + "Used to print state of the definition returned from the server to standard output.\nThe node state is shown in the comments.\nThis is the format used in the check point file, but with indentation.\nSince this is essentially the defs format with state in the comments,it allows the definition to be migrated to future version of ecflow.\nThe output includes edit history but excludes externs.\nWhen the definition is reloaded *NO* checking is done.", + "The following shows a summary of the features associated with each choice:\n --get --get_state --migrate\nAuto generate externs Yes Yes No\nChecking on reload Yes Yes No\nEdit History No No Yes\nShow trigger AST No Yes No", + "Usage:\n --migrate # show all suites\n --migrate=/s1 # show state for suite s1\n" + ] + }, { "name": "news", "kind": "user", From b6a5d993a075660e84a21211f622d2072c07bea9 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 14:17:37 +0100 Subject: [PATCH 20/49] Add ch_register/drop/drop_user/add/rem/auto_add/suites to help manifest Migrates all seven ClientHandleCmd actions, each registered as its own CLI option by the same ClientHandleCmd class dispatching on an Api enum value. --- docs/client_api/help.json | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index a5af61f7c..2d858b2b2 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -42,6 +42,74 @@ "Usage::\n --archive=/s1 # archive suite s1\n --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2\n --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" ] }, + { + "name": "ch_add", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Add a set of suites, to an existing handle.", + "description": [ + "Add a set of suites, to an existing handle.\n arg1 = handle(integer) # The handle must be an integer that is > 0\n arg2 = names # should be a list of suite names, names not in the definition are ignored\nUsage:\n --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10\nAn error is returned if the handle had not previously been registered\nThe handle is created with --ch_register command\nTo list all suites and handles use --ch_suites" + ] + }, + { + "name": "ch_auto_add", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Change an existing handle so that new suites can be added automatically.", + "description": [ + "Change an existing handle so that new suites can be added automatically.\n arg1 = handle(integer) # The handle must be an integer that is > 0\n arg2 = true | false # true means add new suites to my list, when they are created\nUsage:\n --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it\n --ch_auto_add=10 false # modify handle 10 so that no new suites are added\nThe handle is created with --ch_register command\nTo list all suites and handles use --ch_suites" + ] + }, + { + "name": "ch_drop", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Drop/de-register the client handle.", + "description": [ + "Drop/de-register the client handle.\nUn-used handle should be dropped otherwise they will stay, in the server.\n arg1 = handle(integer) # The handle must be an integer that is > 0\nUsage:\n --ch_drop=10 # drop the client handle 10\nAn error is returned if the handle had not previously been registered\nThe handle stored on the local client is set to zero\nTo list all suites and handles use --ch_suites" + ] + }, + { + "name": "ch_drop_user", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Drop/de-register all handles associated with the given user.", + "description": [ + "Drop/de-register all handles associated with the given user.\nIf no user provided will drop for current user. Client must ensure un-used handle are dropped\notherwise they will stay, in the server.\n arg1 = user # The user to be drooped, if left empty drop current user \nUsage:\n --ch_drop_user=ma0 # drop all handles associated with user ma0\n --ch_drop_user # drop all handles associated with current user\nAn error is returned if no registered handles\nTo list all suites and handles use --ch_suites" + ] + }, + { + "name": "ch_register", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Register interest in a set of suites.", + "description": [ + "Register interest in a set of suites.\nIf a definition has lots of suites, but the client. is only interested in a small subset,\nThen using this command can reduce network bandwidth and synchronisation will be quicker.\nThis command will create a client handle, which must be used for any other changes.\nThe newly created handle can be shown with the --ch_suites command\nDeleted suites will stay registered, and must be explicitly removed/dropped.\nNote: Suites can be registered before they are loaded into the server\nThis command affects news() and sync() commands\n arg1 = true | false # true means add new suites to my list, when they are created\n arg2 = names # should be a list of suite names, names not in the definition are ignored\nUsage:\n --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites\n --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only\n --ch_register=false # register handle, suites will be added later on\n --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites\n # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first\nTo list all suites and handles use --ch_suites" + ] + }, + { + "name": "ch_rem", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Remove a set of suites, from an existing handle.", + "description": [ + "Remove a set of suites, from an existing handle.\n arg1 = handle(integer) # The handle must be an integer that is > 0\n arg2 = names # should be a list of suite names, names not in the definition are ignored\nUsage:\n --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10\nThe handle is created with --ch_register command\nTo list all suites and handles use --ch_suites" + ] + }, + { + "name": "ch_suites", + "kind": "user", + "visibility": "public", + "implementation": "ClientHandleCmd", + "summary": "Shows all the client handles, and the suites they reference", + "description": ["Shows all the client handles, and the suites they reference"] + }, { "name": "check", "kind": "user", From 6295d54b879e4aaf7a8b6bdc0f88b527a071a819 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 14:45:56 +0100 Subject: [PATCH 21/49] Add fifteen single-action commands to help manifest Migrates begin, check_pt, delete, edit_script, file, force, free-dep, load, log, msg, order, replace, requeue, run, and server_version -- each a single-action UserCmd subclass with its own addOption(). Descriptions verified byte-for-byte against each class's add_options() literal or named desc()-style function, and live --help output confirmed unchanged. --- docs/client_api/help.json | 162 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 2d858b2b2..c220616a9 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -42,6 +42,16 @@ "Usage::\n --archive=/s1 # archive suite s1\n --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2\n --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" ] }, + { + "name": "begin", + "kind": "user", + "visibility": "public", + "implementation": "BeginCmd", + "summary": "Begin playing the definition in the server.", + "description": [ + "Begin playing the definition in the server.\nExpects zero or a single quoted string.\n arg1 = suite-name | Nothing | force\n play the chosen suite, if no arg specified, play all suites, in the definition\n force means reset the begin status on the suites and bypass checks.\n This is only required if suite-name is provide as the first argument\n Using force can cause the creation of zombies\nUsage:\n--begin # will begin all suites\n--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted\n--begin=\"mySuite\" # begin playing suite of name 'mySuite'\n--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check" + ] + }, { "name": "ch_add", "kind": "user", @@ -130,6 +140,16 @@ "Test hierarchical Job generation only, for chosen Node.\nThe jobs are generated independent of the dependencies\nThis will generate the jobs *only*, i.e. no job submission. Used for checking job generation only\n arg = node path | arg = NULL\n If no node path specified generates for all Tasks in the definition. For Test only" ] }, + { + "name": "check_pt", + "kind": "user", + "visibility": "public", + "implementation": "CheckPtCmd", + "summary": "Forces the definition file in the server to be written to disk *or* allow mode,", + "description": [ + "Forces the definition file in the server to be written to disk *or* allow mode,\ninterval and alarm to be changed.\nWhenever the check pt file is written to disk, it is measured.\nIf the time to save to disk is greater than the default of 30 seconds,\nthen an alarm is raised. This can be seen in the GUI as a late flag on the server.\nOnce the late flag has been set it will need to manually cleared in the GUI\nor by using --alter functionality\nNote excessive save times can interfere with job scheduling.\nThe alarm threshold can be changed. See below.\n arg1 = (optional) mode [ never | on_time | on_time: | always | ]\n never : Never check point the definition in the server\n on_time : Turn on automatic check pointing at interval stored on server\n on_time : Turn on automatic check point, with the specified interval in seconds\n alarm : Modify the alarm notification time for check pt saving to disk\n always : Check point at any change in node tree, *NOT* recommended for large definitions\n : This specifies the interval in seconds when server should automatically check pt.\n This will only take effect of mode is on_time/CHECK_ON_TIME\n Should ideally be a value greater than 60 seconds, default is 120 seconds\nUsage:\n --check_pt\n Immediately check point the definition held in the server\n --check_pt=never\n Switch off check pointing\n --check_pt=on_time\n Start automatic check pointing at the interval stored in the server\n --check_pt=180\n Change the check pt interval to 180 seconds\n --check_pt=on_time:90\n Change mode and interval, to automatic check pointing every 90 seconds\n --check_pt=alarm:35\n Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds\n set the late flag on the server." + ] + }, { "name": "complete", "kind": "task", @@ -169,6 +189,16 @@ "summary": "Enables debug output from the server", "description": ["Enables debug output from the server"] }, + { + "name": "delete", + "kind": "user", + "visibility": "public", + "implementation": "DeleteCmd", + "summary": "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.", + "description": [ + "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.\n arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted tasks\n arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt\n arg3 = node paths | _all_ # _all_ means delete all suites\n # node paths must start with a leading '/'\nUsage:\n --delete=_all_ # Delete all suites in server. Use with care.\n --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt\n --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted\n --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt" + ] + }, { "name": "edit_history", "kind": "user", @@ -179,6 +209,21 @@ "Returns the edit history associated with a Node.\nCan also be used to clear the edit history.\nUsage::\n --edit_history=/s1/f1/t1 # return history of changes for the given node\n --edit_history=clear # clear/purge *ALL* edit history from all nodes.\n" ] }, + { + "name": "edit_script", + "kind": "user", + "visibility": "public", + "implementation": "EditScriptCmd", + "summary": "Allows user to edit, pre-process and submit the script.", + "description": [ + "Allows user to edit, pre-process and submit the script.\nWill allow pre-processing of arbitrary file with 'pre_process_file' option\n arg1 = path to task # The path to the task/alias\n arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ]\n edit : will return the script file to standard out. The script will\n include used variables enclosed between %comment/%end at the\n start of the file\n pre_process: Will return the script file to standard out.The script will\n include used variables enclosed between %comment/%end at the\n start of the file and with all %include expanded\n submit: Will extract the used variables from the supplied file, i.e\n between the %comment/%end and use these them to generate the\n job using the ecf file accessible from the server\n pre_process_file: Will pre process the user supplied file.\n Will expand includes,variable substitution,\n remove manual & comment sections.\n submit_file: Like submit, but the supplied file, is submitted by the server\n The last 2 options allow complete freedom to debug the script file\n arg3 = [ path_to_script_file ]\n needed for option [ pre_process_file | submit_file ]\n arg4 = create_alias (optional) default value is false, for use with 'submit_file' option\n arg5 = no_run (optional) default value is false, i.e immediately run the alias\n is no_run is specified the alias in only created\nUsage:\n--edit_script=/path/to/task edit > script_file\n server returns script with the used variables to standard out\n The user can choose to edit this file", + "--edit_script=/path/to/task pre_process > pre_processed_script_file\n server will pre process the ecf file accessible from the server\n (i.e expand all %includes) and return the file to standard out", + "--edit_script=/path/to/task submit script_file\n Will extract the used variables in the 'script_file' and will uses these\n variables during variable substitution of the ecf file accessible by the\n server. This is then submitted as a job", + "--edit_script=/path/to/task pre_process_file file_to_pre_process\n The server will pre-process the user supplied file and return the contents\n to standard out. This pre-processing is the same as job file processing,\n but on a arbitrary file", + "--edit_script=/path/to/task submit_file file_to_submit\n Will extract the used variables in the 'file_to_submit' and will uses these\n variables during variable substitution, the file is then submitted for job\n generation by the server", + "--edit_script=/path/to/task submit_file file_to_submit create_alias\n Like the the previous example but will create and run as an alias" + ] + }, { "name": "event", "kind": "task", @@ -209,6 +254,27 @@ "ecflow_client --event=ev clear # clear the event, use when event initial value is set" ] }, + { + "name": "file", + "kind": "user", + "visibility": "public", + "implementation": "CFileCmd", + "summary": "Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ]", + "description": [ + "Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ]\nBy default will return the script.\n arg1 = path to node\n arg2 = (optional) [ script | job | jobout | manual | kill | stat ]\n kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill\n stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat\n arg3 = (optional) max_lines = 10000 " + ] + }, + { + "name": "force", + "kind": "user", + "visibility": "public", + "implementation": "ForceCmd", + "summary": "Force a node to a given state, or set its event.", + "description": [ + "Force a node to a given state, or set its event.\nWhen a task is set to complete, it may be automatically re-queued if it has\nmultiple future time dependencies. However each time we force a complete it will\nexpire any time based attribute on that node. When the last time based attribute\nexpires, the node will stay in a complete state.\nThis behaviour allow Repeat values to be incremented interactively.\nA repeat attribute is incremented when all the child nodes are complete\nin this case the child nodes are automatically re-queued.\n arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ]\n arg2 = (optional) recursive\n Applies state to node and recursively to all its children\n arg3 = (optional) full\n Set repeat variables to last value, only works in conjunction\n with recursive option\n arg4 = path_to_node or path_to_node:: paths must begin with '/'\nUsage:\n --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete\n --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task\n --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1\nEffect:\n Consider the effect of forcing complete when the current time is at 09:00\n suite s1\n task t1; time 12:00 # will complete straight away\n task t2; time 10:00 13:00 01:00 # will complete on fourth attempt", + " --force=complete /s1/t1 /s1/t2\n When we have a time range(i.e as shown with task t2), it is re-queued and the\n next time slot is incremented for each complete, until it expires, and the task completes.\n Use the Why command, to show next run time (i.e. next time slot)" + ] + }, { "name": "force-dep-eval", "kind": "user", @@ -217,6 +283,16 @@ "summary": "Force dependency evaluation. Used for DEBUG only.", "description": ["Force dependency evaluation. Used for DEBUG only."] }, + { + "name": "free-dep", + "kind": "user", + "visibility": "public", + "implementation": "FreeDepCmd", + "summary": "Free dependencies for a node. Defaults to triggers", + "description": [ + "Free dependencies for a node. Defaults to triggers\nAfter freeing the time related dependencies (i.e time,today,cron)\nthe next time slot will be missed.\n arg1 = (optional) trigger\n arg2 = (optional) all\n Free trigger, date and all time dependencies\n arg3 = (optional) date\n Free date dependencies\n arg4 = (optional) time\n Free all time dependencies i.e time, day, today, cron\n arg5 = List of paths. At least one required. Must start with a leading '/'\nUsage:\n --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2\n --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1\n --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1" + ] + }, { "name": "get", "kind": "user", @@ -320,6 +396,26 @@ ], "usage": ["ecflow_client --label=progressed merlin"] }, + { + "name": "load", + "kind": "user", + "visibility": "public", + "implementation": "LoadDefsCmd", + "summary": "Check and load definition or checkpoint file into server.", + "description": [ + "Check and load definition or checkpoint file into server.\nThe loaded definition will be checked for valid trigger and complete expressions,\nadditionally in-limit references to limits will be validated.\nIf the server already has the 'suites' of the same name, then a error message is issued.\nThe suite's can be overwritten if the force option is used.\nTo just check the definition and not send to server, use 'check_only'\nThis command can also be used to load a checkpoint file into the server\n arg1 = path to the definition file or checkpoint file\n arg2 = (optional) [ force | check_only | print | stats ] # default = false for all\nUsage:\n--load=/my/home/exotic.def # will error if suites of same name exists\n--load=/my/home/exotic.def force # overwrite suite's of same name in the server\n--load=/my/home/exotic.def check_only # Just check, don't send to server\n--load=/my/home/exotic.def stats # Show defs statistics, don't send to server\n--load=host1.3141.check # Load checkpoint file to the server\n--load=host1.3141.check print # print definition to standard out in defs format\n" + ] + }, + { + "name": "log", + "kind": "user", + "visibility": "public", + "implementation": "LogCmd", + "summary": "Get,clear,flush or create a new log file.", + "description": [ + "Get,clear,flush or create a new log file.\nThe user must ensure that a valid path is specified.\nSpecifying '--log=get' with a large number of lines from the server,\ncan consume a lot of **memory**. The log file can be a very large file,\nhence we use a default of 100 lines, optionally the number of lines can be specified.\n arg1 = [ get | clear | flush | new | path ]\n get - Outputs the log file to standard out.\n defaults to return the last 100 lines\n The second argument can specify how many lines to return\n clear - Clear the log file of its contents.\n flush - Flush and close the log file. (only temporary) next time\n server writes to log, it will be opened again. Hence it best\n to halt the server first\n new - Flush and close the existing log file, and start using the\n the path defined for ECF_LOG. By changing this variable\n a new log file path can be used\n Alternatively an explicit path can also be provided\n in which case ECF_LOG is also updated\n path - Returns the path name to the existing log file\n arg2 = [ new_path | optional last n lines ]\n if get specified can specify lines to get. Value must be convertible to an integer\n Otherwise if arg1 is 'new' then the second argument must be a path\nUsage:\n --log=get # Write the last 100 lines of the log file to standard out\n --log=get 200 # Write the last 200 lines of the log file to standard out\n --log=clear # Clear the log file. The log is now empty\n --log=flush # Flush and close log file, next request will re-open log file\n --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG\n --log=new # Close and flush log file, and create a new log file using ECF_LOG variable\n" + ] + }, { "name": "meter", "kind": "task", @@ -357,6 +453,16 @@ "Usage:\n --migrate # show all suites\n --migrate=/s1 # show state for suite s1\n" ] }, + { + "name": "msg", + "kind": "user", + "visibility": "public", + "implementation": "LogMessageCmd", + "summary": "Writes the input string to the log file.", + "description": [ + "Writes the input string to the log file.\n arg1 = string\nUsage:\n --msg=\"place me in the log file\"" + ] + }, { "name": "news", "kind": "user", @@ -367,6 +473,19 @@ "Returns true if state of server definition changed.\n*Important* for use with c++/python interface only.\nRequires Given a client handle, change and modify number determine if server changed since last call\nThis relies on user calling sync after news to update the locally stored modify and change numbers.\nThese numbers are then used in the next call to news." ] }, + { + "name": "order", + "kind": "user", + "visibility": "public", + "implementation": "OrderNodeCmd", + "summary": "Re-orders the nodes held by the server", + "description": [ + "Re-orders the nodes held by the server\n arg1 = node path\n arg2 = [ top | bottom | alpha | order | up | down | runtime]\nIt should be noted that in the absence of triggers and time/date dependencies,\nthe tasks are submitted in order.\nThis changes the order and hence affects the submission order::", + " o top raises the node within its parent, so that it is first\n o bottom lowers the node within its parent, so that it is last\n o alpha Arranges for all the peers of selected note to be sorted alphabetically (case-insensitive)\n o order Arranges for all the peers of selected note to be sorted in reverse alphabet(case-insensitive)\n o up Moves the selected node up one place amongst its peers\n o down Moves the selected node down one place amongst its peers", + " o runtime Orders the nodes according to state change runtime\n for families by accumulated runtime of its children\n useful to submit the task that take longer earlier", + "This command can fail because:\n- The node path does not exist in the server\n- The order_type is not does not match one of arg2\nUsage:\n --order=/suite/f1 top # move node f1 to the top" + ] + }, { "name": "ping", "kind": "user", @@ -482,6 +601,29 @@ "\nUsage:\n --reloadwsfile" ] }, + { + "name": "replace", + "kind": "user", + "visibility": "public", + "implementation": "ReplaceNodeCmd", + "summary": "Replaces a node in the server, with the given path", + "description": [ + "Replaces a node in the server, with the given path\nCan also be used to add nodes in the server\n arg1 = path to node\n must exist in the client defs(arg2). This is also the node we want to\n replace in the server\n arg2 = path to client definition file\n provides the definition of the new node\n arg3 = (optional) [ parent | false ] (default = parent)\n create parent families or suite as needed, when arg1 does not\n exist in the server\n arg4 = (optional) force (default = false) \n Force the replacement even if it causes zombies to be created\nReplace can fail if:\n- The node path(arg1) does not exist in the provided client definition(arg2)\n- The client definition(arg2) must be free of errors\n- If the third argument is not provided, then node path(arg1) must exist in the server\n- Nodes to be replaced are in active/submitted state, in which case arg4(force) can be used", + "Replace will preserve the suspended status, if this is not required please re-queue first\nAfter replace is done, we check trigger expressions. These are reported to standard output.\nIt is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\nPlease note, you can use --check to check trigger expression and limits in the server.\nFor more information use --help check.", + "Usage:\n --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1\n --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted" + ] + }, + { + "name": "requeue", + "kind": "user", + "visibility": "public", + "implementation": "RequeueNodeCmd", + "summary": "Re queues the specified node(s)", + "description": [ + "Re queues the specified node(s)\n If any child of the specified node(s) is in a suspended state, this state is cleared\nRepeats are reset to their starting values, relative time attributes are reset.\n arg1 = (optional) [ abort | force ]\n abort = re-queue only aborted tasks below node\n force = Force the re-queueing even if there are nodes that are active or submitted\n = Checks if any tasks are in submitted or active states below the node\n if so does nothing. Otherwise re-queues the node.\n arg2 = list of node paths. The node paths must begin with a leading '/' character", + "Usage:\n --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1\n --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.\n --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'" + ] + }, { "name": "restart", "kind": "user", @@ -525,6 +667,16 @@ "Resume the given node. This allows job generation for the given node, or any child node.\nUsage::\n --resume=/s1/f1/t1 # resume task s1/f1/t1\n --resume=/s1 /s2 # resume suites /s1 and /s2\n" ] }, + { + "name": "run", + "kind": "user", + "visibility": "public", + "implementation": "RunNodeCmd", + "summary": "Ignore triggers, limits, time or date dependencies, just run the Task.", + "description": [ + "Ignore triggers, limits, time or date dependencies, just run the Task.\nWhen a job completes, it may be automatically re-queued if it has a cron\nor multiple time dependencies. If we have multiple time based attributes,\nthen each run, will expire the time.\nWhen we run before the time, we want to avoid re-running the task then\na flag is set, so that it is not automatically re-queued.\nA repeat attribute is incremented when all the child nodes are complete\nin this case the child nodes are automatically re-queued.\nHence this command can be aid, in allowing a Repeat attribute to be incremented\n arg1 = (optional)force\n Forcibly run, even if there are nodes that are active or submitted\n This can result in zombie creation\n arg2 = node path(s). The paths must begin with a leading '/' character.\n If the path is /suite/family will recursively run all tasks\n When providing multiple paths avoid running the same task twice\nExample:\n --run=/suite/t1 # run task t1\nEffect:\n task t1; time 12:00 # will complete if run manually\n task t2; time 10:00 13:00 01:00 # will run 4 times before completing\n When we have a time range(i.e as shown with task t2), then next time slot\n is incremented for each run, until it expires, and the task completes.\n Use the Why command, to show next run time (i.e. next time slot)" + ] + }, { "name": "server_load", "kind": "user", @@ -541,6 +693,16 @@ "> display ..png\n> feh ..png\n> eog ..png\n> xdg-open ..png\n> w3m ..png\n" ] }, + { + "name": "server_version", + "kind": "user", + "visibility": "public", + "implementation": "ServerVersionCmd", + "summary": "Returns the version number of the server", + "description": [ + "Returns the version number of the server\nUsage:\n --server_version\n Writes the version to standard output\n" + ] + }, { "name": "shutdown", "kind": "user", From 80eb4c479b82f8f29402b7b2fbae2d2779cb0a02 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 15:11:30 +0100 Subject: [PATCH 22/49] Add alter to help manifest Migrates AlterCmd's single alter command. Its argument shape is genuinely conditional per operation (delete/change/add/set_flag/ clear_flag/sort each accept different attribute types), so per the already-resolved decision this stays a single prose block rather than structured JSON. --- docs/client_api/help.json | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index c220616a9..ae62ae800 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -29,6 +29,52 @@ ], "usage": ["ecflow_client --abort=reasonX"] }, + { + "name": "alter", + "kind": "user", + "visibility": "public", + "implementation": "AlterCmd", + "summary": "Alter the node according to the options.", + "description": [ + "Alter the node according to the options.", + "arg1 = [ delete | change | add | set_flag | clear_flag | sort ]", + "arg2 = For delete:\n [ variable | time | today | date | day | cron | event | meter | late | generic |\n queue | label | trigger | complete | repeat | limit | inlimit | limit_path |\n zombie | aviso | mirror ]", + " For change:\n [ variable | clock_type | clock_gain | clock_date | clock_sync | event | meter |\n label | trigger | complete | repeat | limit_max | limit_value | defstatus |\n late | time | today | aviso | mirror ]", + " For add:\n [ variable | time | today | date | day | zombie | event | meter | late | limit |\n inlimit | label | aviso | mirror ]", + " For set_flag or clear_flag:\n [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed |\n statuscmd_failed | killcmd_failed | no_script | killed | status | late |\n message complete | queue_limit | task_waiting | locked | zombie | archived |\n restored | threshold | log_error | checkpt_error ]", + " For sort:\n [ event | meter | label | variable| limit | all ]", + "arg3 = [ | ]", + "arg4 = ", + "arg5 = ( (...)) - at least one node path required.", + "*Important Notes*", + " * All paths must start with a leading '/' character.", + " * To update, create or remove server variables use '/' for path.", + " * When updating unnamed attributes (Repeat, Trigger, Complete, ...) the name/arg3 is not necessary.", + " * After changing the clock the suite needs to be re-queued for the change to take effect.", + " * When adding or updating node attributes (e.g. variable, meter, event, label, limits, late)\n the name (arg3) and value (arg4) must be quoted.", + " * When sorting attributes, 'recursive' can be used as the value (arg3).", + " * When adding a meter, the value (arg4) is expected to be a comma-separated triplet\n of numerical values the form \",,\" (n.b. no spaces are allowed).", + " * When adding an event, the non-optional value (arg4) must be either \"set\" or \"clear\".", + " * When adding or updating aviso and mirror attributes, the value (arg4) is expected to be\n a quoted list of configuration options. For example:\n * for aviso, \"--remote_path /s1/f1/t2 --remote_host host --polling 20 --remote_port 3141 --ssl)\"\n * for mirror, \"--listener '{ \\\"event\\\": \\\"mars\\\", \\\"request\\\": { \\\"class\\\": \"od\" } }'\n --url http://aviso/ --schema /path/to/schema --polling 60\"", + " * For both aviso and mirror, the special value \"reload\" forces reloading the configuration.\n This is typically useful after updating variables used to configure these kind of attributes.", + "Usage:", + " ecflow_client --alter=add variable \"value\" / # add server variable\n ecflow_client --alter=add variable \"value\" /path/to/node # add node variable", + " ecflow_client --alter=add time \"+00:20\" /path/to/node", + " ecflow_client --alter=add date \"01.*.*\" /path/to/node", + " ecflow_client --alter=add day \"sunday\" /path/to/node", + " ecflow_client --alter=add label \"label_value\" /path/to/node", + " ecflow_client --alter=add event \"set\"|\"clear\" /path/to/node", + " ecflow_client --alter=add meter \",,value\" /path/to/node", + " ecflow_client --alter=add late \"-s 00:01 -a 14:30 -c +00:01\" /path/to/node", + " ecflow_client --alter=add limit mars \"100\" /path/to/node", + " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"10\" /path/to/node", + " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-s 10\" /path/to/node", + " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-n 10\" /path/to/node", + " # zombie attributes have the following structure:\n `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time`\n zombie_type = \"user\" | \"ecf\" | \"path\" | \"ecf_pid\" | \"ecf_passwd\" | \"ecf_pid_passwd\"\n client_side_action = \"fob\" | \"fail\" | \"block\"\n server_side_action = \"adopt\" | \"delete\" | \"kill\"\n child = \"init\" | \"event\" | \"meter\" | \"label\" | \"wait\" | \"abort\" | \"complete\" | \"queue\"\n zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60", + " ecflow_client --alter=add zombie \"ecf:fail::\" /path/to/node # ask system zombies to fail\n ecflow_client --alter=add zombie \"user:fail::\" /path/to/node # ask user generated zombies to fail\n ecflow_client --alter=add zombie \"path:fail::\" /path/to/node # ask path zombies to fail", + " ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED\n ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode\n" + ] + }, { "name": "archive", "kind": "user", From 77246945116e4eeb914db7b201e820ab6ec83438 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 15:25:47 +0100 Subject: [PATCH 23/49] Add query/plug to help manifest Migrates QueryCmd's query command and PlugCmd's plug command. --- docs/client_api/help.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index ae62ae800..bd87904c3 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -542,6 +542,28 @@ "Check if server is running on given host/port. Result reported to standard output.\nUsage:\n --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144\n --ping --host=fred # Check if server alive on host fred and port ECF_PORT,\n # otherwise default port of 3141\n --ping # Check if server alive by using environment variables\n # ECF_HOST and ECF_PORT\nIf ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141" ] }, + { + "name": "plug", + "kind": "user", + "visibility": "public", + "implementation": "PlugCmd", + "summary": "Plug command is used to move nodes.", + "description": [ + "Plug command is used to move nodes.\nThe destination node can be on another server In which case the destination\npath should be of the form ':/suite/family/task\n arg1 = path to source node\n arg2 = path to the destination node\nThis command can fail because:\n- Source node is in a 'active' or 'submitted' state\n- Another user already has an lock\n- source/destination paths do not exist on the corresponding servers\n- If the destination node path is empty, i.e. only host:port is specified,\n then the source node must correspond to a suite.\n- If the source node is added as a child, then its name must be unique\n amongst its peers\nUsage:\n --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)" + ] + }, + { + "name": "query", + "kind": "user", + "visibility": "public", + "implementation": "QueryCmd", + "summary": "Query the status of attributes", + "description": [ + "Query the status of attributes\n i.e state,dstate,repeat,event,meter,label,variable or trigger expression without blocking\n - state return [unknown | complete | queued | aborted | submitted | active] to standard out\n - dstate return [unknown | complete | queued | suspended | aborted | submitted | active] to standard out\n - repeat returns current value as a string to standard out\n - event return 'set' | 'clear' to standard out\n - meter return value of the meter to standard out\n - limit return current value of limit to standard out\n - limit_max return limit max value to standard out\n - label return new value otherwise the old value\n - variable return value of the variable, repeat or generated variable to standard out,\n will search up the node tree. When path is '/', the variable is looked up on the\n server itself, i.e. 'ecflow_client --query variable /:name'\n - trigger returns 'true' if the expression is true, otherwise 'false'", + "If this command is called within a '.ecf' script we will additionally log the task calling this command\nThis is required to aid debugging for excessive use of this command\nThe command will fail if the node path to the attribute does not exist in the definition and if:\n - repeat The repeat is not found\n - event The event is not found\n - meter The meter is not found\n - limit/limit_max The limit is not found\n - label The label is not found\n - variable No user or generated variable or repeat of that name found on node or its parents,\n or (when path is '/') no user or server variable of that name found on the server\n - trigger Trigger does not parse, or reference to nodes/attributes in the expression are not valid\nArguments:\n arg1 = [ state | dstate | repeat | event | meter | label | variable | trigger | limit | limit_max ]\n arg2 = | :name where name is name of a event, meter, label, limit or variable.\n path '/' represents the server itself, and can only be used with 'state' or 'variable'\n arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat", + "Usage:\n ecflow_client --query state / # return top level state to standard out\n ecflow_client --query state /path/to/node # return node state to standard out\n ecflow_client --query dstate /path/to/node # state that can included suspended\n ecflow_client --query repeat /path/to/node # return the current value as a string\n ecflow_client --query repeat /path/to/node prev # return the previous value as a string\n ecflow_client --query repeat /path/to/node next # return the next value as a string\n ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out\n ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out\n ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out\n ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out\n ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out\n ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to standard out\n ecflow_client --query variable /:var_name # returns the server variable value to standard out\n ecflow_client --query trigger /path/to/node/with/trigger \"/suite/task == complete\" # return true if expression evaluates false otherwise\n" + ] + }, { "name": "queue", "kind": "task", From 057580338c3867f68733304d6e998ddbc9daf903 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 15:35:03 +0100 Subject: [PATCH 24/49] Add group to help manifest Migrates GroupCTSCmd's single group command -- registered by default in CtsCmdRegistry (addGroupCmd defaults to true), unlike every other command here. --- docs/client_api/help.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index bd87904c3..a480b06b7 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -359,6 +359,16 @@ "Get state data. For the whole suite definition or individual nodes.\nThis will include event, meter, node state, trigger and time state.\nThe output is written to standard out.\n arg = NULL | arg = node path\nUsage:\n --get_state # gets the definition from the server,and writes to standard out\n --get_state=/s1 # gets the suite from the server,and writes to standard out" ] }, + { + "name": "group", + "kind": "user", + "visibility": "public", + "implementation": "GroupCTSCmd", + "summary": "Allows a series of ';' separated commands to be grouped and executed as one.", + "description": [ + "Allows a series of ';' separated commands to be grouped and executed as one.\nSome commands like halt, shutdown and terminate will prompt the user. To bypass the prompt\nprovide 'yes' as an additional parameter. See example below.\n arg = string\nUsage:\n --group=\"halt=yes; reloadwsfile; restart;\"\n # halt server,bypass the confirmation prompt,\n # reload white list file, restart server\n --group=\"get; show\" # get server defs, and write to standard output\n --group=\"get=/s1; show state\" # get suite 's1', and write state to standard output" + ] + }, { "name": "halt", "kind": "user", From 47e6d4ae7a1ea3d4913a178822869eeed6688cc6 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 15:51:17 +0100 Subject: [PATCH 25/49] Add add/remove command-options to help manifest Migrates the add command-option on init and the remove command-option on complete, both registered inline in their owning command's addOption(), as command-option entries linked via the manifest's command field. add is in Help.cpp's CommandFilter::known_options (no env-var banner at runtime); remove is not (gets the full banner) -- both behaviors preserved and verified byte-for-byte against live --help output. --- docs/client_api/help.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index a480b06b7..45dc4492b 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -1064,6 +1064,22 @@ "description": [ "Enables the display of client environment settings and execution details.\nHas the same effect as setting environment variable ECF_DEBUG_CLIENT." ] + }, + { + "name": "add", + "kind": "command-option", + "command": "init", + "summary": "Add variables e.g. name1=value1 name2=value2. Can only be used in combination with --init command.", + "description": [ + "Add variables e.g. name1=value1 name2=value2. Can only be used in combination with --init command." + ] + }, + { + "name": "remove", + "kind": "command-option", + "command": "complete", + "summary": "remove variables i.e name name2", + "description": ["remove variables i.e name name2"] } ], "environment_variables": [ From 1c2872bb8ff5847361bfdb6cd55faa555afd8f18 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 15:58:18 +0100 Subject: [PATCH 26/49] Add why/show to help manifest as group-only commands Migrates CtsNodeCmd's why action and ShowCmd's show command, both with visibility "group-only" since they can only be used inside --group and are registered normally in CtsCmdRegistry alongside every public command. --- docs/client_api/help.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 45dc4492b..09b29f10b 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -781,6 +781,18 @@ "Returns the version number of the server\nUsage:\n --server_version\n Writes the version to standard output\n" ] }, + { + "name": "show", + "kind": "user", + "visibility": "group-only", + "implementation": "ShowCmd", + "summary": "Used to print state of the definition returned from the server to standard output.", + "description": [ + "Used to print state of the definition returned from the server to standard output.\nThis command can *only* be used in a group command, and will only work if it is\npreceded with a get command. See examples below.\n arg1 = [ defs | state | migrate ] \nThe output of show has several options: i.e\n o no arguments: With no arguments, print the definition structure to standard output\n Extern's are automatically added, allowing the output to be reloaded into the server\n i.e --group=\"get ; show\"\n o state:\n This will output definition structure along with all the state information.\n This will include the trigger expressions, abstract syntax tree as comments.\n Excludes the edit history\n o migrate:\n This will output definition structure along with all the state information.\n The node state is shown in the comments.\n This format allows the definition to be migrated to future version of ecflow.\n The output includes edit history but excludes externs.\n When the definition is reloaded *NO* checking is done.", + "The following shows a summary of the features associated with each choice\n DEFS STATE MIGRATE\nAuto generate externs Yes Yes No\nChecking on reload Yes Yes No\nEdit History No No Yes\ntrigger AST No Yes No", + "Usage:\n --group=\"get ; show\"\n --group=\"get ; show defs\" # same as the previous example\n --group=\"get ; show state\" # Show all state for the node tree\n --group=\"get ; show migrate\" # Shows state and allows migration\n --group=\"get=/s1; show\" # show state for the node only\n --group=\"get=/s1; show state\"" + ] + }, { "name": "shutdown", "kind": "user", @@ -902,6 +914,16 @@ ], "usage": ["ecflow_client --wait=\"/suite/taskx == complete\""] }, + { + "name": "why", + "kind": "user", + "visibility": "group-only", + "implementation": "CtsNodeCmd", + "summary": "Show the reason why a node is not running.", + "description": [ + "Show the reason why a node is not running.\nCan only be used with the group command. The group command must include a \n'get' command(i.e returns the server defs)\nThe why command take a optional string argument representing a node path\nWill return reason why the node is holding and for all its children.\nIf no arguments supplied will report on all nodes\n arg = node path | arg = NULL\nUsage:\n --group=\"get; why\" # returns why for all holding nodes\n --group=\"get; why=/suite/family\" # returns why for a specific node" + ] + }, { "name": "zombie_get", "kind": "user", From a5f270e2f4bfcfb91a993e4d03d262df6aa298ff Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 16:00:55 +0100 Subject: [PATCH 27/49] Add move to help manifest as an internal command Migrates MoveCmd's single move command, with visibility "internal" since it is never registered in CtsCmdRegistry (created on the fly by PlugCmd) and so has no CLI-reachable --help output to verify against -- confirmed live, "No matching command found". Description verified by exact regex extraction from MoveCmd::desc()'s add_options() literal instead. --- docs/client_api/help.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 09b29f10b..31611fa7c 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -509,6 +509,16 @@ "Usage:\n --migrate # show all suites\n --migrate=/s1 # show state for suite s1\n" ] }, + { + "name": "move", + "kind": "user", + "visibility": "internal", + "implementation": "MoveCmd", + "summary": "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api.", + "description": [ + "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api." + ] + }, { "name": "msg", "kind": "user", From 4b954844e6eb3d0420c990be954fd6057dc408b6 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 16:09:32 +0100 Subject: [PATCH 28/49] Remove unused verbatim block type from help manifest The description_block schema allowed either a plain string or a {"verbatim": string} object, intended for preformatted content such as CtsCmd's ASCII-art tables. In practice every command migrated so far, including the ones with the richest preformatted output, reproduces its content byte-for-byte through the plain string form alone: joining blocks with a blank line is a lossless round-trip regardless of how many blank lines the original text contains. Drop the verbatim object type from help.schema.json and simplify HelpCatalog::description_for() to match, removing the now-dead branch that handled it. --- docs/client_api/help.schema.json | 15 +++------------ libs/base/src/ecflow/base/HelpCatalog.cpp | 7 +------ libs/base/src/ecflow/base/HelpCatalog.hpp | 4 +--- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index e36b675b0..f8baceb71 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -29,18 +29,9 @@ }, "$defs": { "description_block": { - "description": "A paragraph of prose, or a preformatted block reproduced verbatim (e.g. CtsCmd's ASCII-art tables).", - "oneOf": [ - { "type": "string", "minLength": 1 }, - { - "type": "object", - "additionalProperties": false, - "required": ["verbatim"], - "properties": { - "verbatim": { "type": "string", "minLength": 1 } - } - } - ] + "description": "A paragraph of prose. Joined with the next block by a blank line; this reproduces preformatted content (e.g. CtsCmd's ASCII-art tables) byte-for-byte too, since any blank lines within such a block round-trip through the same join, without needing a distinct verbatim representation.", + "type": "string", + "minLength": 1 }, "description": { "type": "array", diff --git a/libs/base/src/ecflow/base/HelpCatalog.cpp b/libs/base/src/ecflow/base/HelpCatalog.cpp index 0ab539ff7..b6f72793d 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.cpp +++ b/libs/base/src/ecflow/base/HelpCatalog.cpp @@ -49,12 +49,7 @@ std::optional HelpCatalog::description_for(const std::string& name) if (!text.empty()) { text += "\n\n"; } - if (block.is_string()) { - text += block.get(); - } - else if (block.is_object() && block.contains("verbatim")) { - text += block.at("verbatim").get(); - } + text += block.get(); } return text; } diff --git a/libs/base/src/ecflow/base/HelpCatalog.hpp b/libs/base/src/ecflow/base/HelpCatalog.hpp index a5e07c80a..1d7a2f162 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.hpp +++ b/libs/base/src/ecflow/base/HelpCatalog.hpp @@ -89,9 +89,7 @@ class HelpCatalog { /// Checks commands first, then options, matching @ref find_command and /// @ref find_option order. The entry's "description" blocks are joined the /// same way the paragraphs were originally separated in the C++ source: a - /// blank line between blocks. A verbatim block (e.g. CtsCmd's ASCII-art - /// tables) is reproduced as-is, without a paragraph-break interpretation of - /// its own embedded newlines. + /// blank line between blocks. This reproduces preformatted content as is. /// /// @param name Exact command or option name to look up, e.g. "abort". /// @return The reconstructed description text, or std::nullopt if @p name From e010a3d195cfbbaf7e7713a1b42a5fe9f163eb64 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 16:22:15 +0100 Subject: [PATCH 29/49] Route thrown parse errors through the help manifest CheckPtCmd, BeginCmd, RequeueNodeCmd, FreeDepCmd, CFileCmd, LoadDefsCmd, LogCmd, ForceCmd, RunNodeCmd, EditScriptCmd, AlterCmd, QueryCmd, and PlugCmd each embed their own usage text directly in the errors thrown when create() rejects malformed CLI arguments. That text was a second, independent copy of the same content already carried in the help manifest, left to drift the moment either copy changed. Look each error's text up via HelpCatalog::description_for(), falling back to the original desc()/arg_desc() text when the manifest has no matching entry (there is currently no case where it does not, but the fallback keeps these call sites safe against a future manifest gap). --- .../base/src/ecflow/base/cts/user/AlterCmd.cpp | 13 +++++++------ .../base/src/ecflow/base/cts/user/BeginCmd.cpp | 4 +++- .../base/src/ecflow/base/cts/user/CFileCmd.cpp | 3 ++- .../src/ecflow/base/cts/user/CheckPtCmd.cpp | 18 ++++++++++-------- .../src/ecflow/base/cts/user/EditScriptCmd.cpp | 14 +++++++++----- .../base/src/ecflow/base/cts/user/ForceCmd.cpp | 11 +++++++---- .../src/ecflow/base/cts/user/FreeDepCmd.cpp | 12 ++++++++---- .../src/ecflow/base/cts/user/LoadDefsCmd.cpp | 3 ++- libs/base/src/ecflow/base/cts/user/LogCmd.cpp | 4 +++- libs/base/src/ecflow/base/cts/user/PlugCmd.cpp | 6 ++++-- .../base/src/ecflow/base/cts/user/QueryCmd.cpp | 5 +++-- .../ecflow/base/cts/user/RequeueNodeCmd.cpp | 9 ++++++--- .../src/ecflow/base/cts/user/RunNodeCmd.cpp | 10 +++++++--- 13 files changed, 71 insertions(+), 41 deletions(-) diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp index 04886c848..b2f9324a3 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -20,6 +20,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/Enumerate.hpp" @@ -810,7 +811,7 @@ AlterCmd::Add_attr_type AlterCmd::get_add_attr_type(const std::string& attr_type } ss << valid[i]; } - ss << "] but found " << attr_type << "\n" << AlterCmd::desc(); + ss << "] but found " << attr_type << "\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1063,7 +1064,7 @@ AlterCmd::Delete_attr_type AlterCmd::get_delete_attr_type(const std::string& att } ss << valid[i]; } - ss << "] but found " << attr_type << "\n" << AlterCmd::desc(); + ss << "] but found " << attr_type << "\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1294,7 +1295,7 @@ AlterCmd::Change_attr_type AlterCmd::get_change_attr_type(const std::string& att } ss << valid[i]; } - ss << "]\n" << AlterCmd::desc(); + ss << "]\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1760,7 +1761,7 @@ ecf::Flag::Type AlterCmd::get_flag_type(const std::string& flag_type) const { } ss << valid[i]; } - ss << "]\n" << AlterCmd::desc(); + ss << "]\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); throw std::runtime_error(ss.str()); } return theFlagType; @@ -1790,7 +1791,7 @@ void AlterCmd::check_sort_attr_type(const std::string& attr_type) const { } ss << valid[i]; } - ss << "] but found " << attr_type << "\n" << AlterCmd::desc(); + ss << "] but found " << attr_type << "\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); throw std::runtime_error(ss.str()); } } @@ -1815,7 +1816,7 @@ void AlterCmd::create_sort_attributes(Cmd_ptr& cmd, if (options[2] != "recursive") { throw std::runtime_error(MESSAGE("AlterCmd: sort: Expected third argument to be 'recursive' but found '" << options[2] << "\n" - << AlterCmd::desc())); + << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()))); } value = "recursive"; } diff --git a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp index efc0377c9..4430110f7 100644 --- a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/core/Str.hpp" #include "ecflow/node/NodeAlgorithms.hpp" @@ -184,7 +185,8 @@ void BeginCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A else { throw std::runtime_error(MESSAGE("BeginCmd: Expect zero, one or 2 arguments, but found " << lineTokens.size() << " arguments\n" - << BeginCmd::desc() << "\n")); + << HelpCatalog::description_for("begin").value_or(BeginCmd::desc()) + << "\n")); } } diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp index 7bb2ec6f5..8aab6ace7 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp @@ -17,6 +17,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Converter.hpp" @@ -358,7 +359,7 @@ void CFileCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A if (args.size() < 1) { throw std::runtime_error(MESSAGE("CFileCmd: At least one arguments expected for File. Found " << args.size() << "\n" - << CFileCmd::desc() << "\n")); + << HelpCatalog::description_for("file").value_or(CFileCmd::desc()) << "\n")); } std::string pathToNode = args[0]; diff --git a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp index 3cb45ba19..025eb39c4 100644 --- a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Converter.hpp" @@ -144,11 +145,12 @@ static int parse_check_pt_interval(const std::string& the_arg) { throw std::runtime_error(MESSAGE("check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | always | ]\n" - << arg_desc())); + << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); } if (check_pt_interval <= 0) { - throw std::runtime_error(MESSAGE("check_pt: interval(" << check_pt_interval << ") must be greater than zero :\n" - << arg_desc())); + throw std::runtime_error(MESSAGE("check_pt: interval(" + << check_pt_interval << ") must be greater than zero :\n" + << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); } return check_pt_interval; } @@ -164,12 +166,12 @@ static int parse_check_pt_alarm_time(const std::string& the_arg, int colon_pos) throw std::runtime_error(MESSAGE( "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | alarm::integer> | always | ]\n" - << arg_desc())); + << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); } if (check_pt_alarm_time <= 0) { - throw std::runtime_error(MESSAGE("check_pt: alarm time(" << check_pt_alarm_time - << ") must be greater than zero :\n" - << arg_desc())); + throw std::runtime_error(MESSAGE("check_pt: alarm time(" + << check_pt_alarm_time << ") must be greater than zero :\n" + << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); } return check_pt_alarm_time; } @@ -214,7 +216,7 @@ void CheckPtCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | alarm: | always | ]\n" - << arg_desc())); + << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); } check_pt_interval = parse_check_pt_interval(interval); } diff --git a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp index 44a0b62ea..bb7ce23a2 100644 --- a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/File.hpp" @@ -353,7 +354,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } if (args.size() < 2) { - throw std::runtime_error(MESSAGE("EditScriptCmd:At least 2 arguments required:\n" << EditScriptCmd::desc())); + throw std::runtime_error( + MESSAGE("EditScriptCmd:At least 2 arguments required:\n" + << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); } std::string path_to_task = args[0]; @@ -397,7 +400,7 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } ss << edit_types[i]; } - ss << "]\n" << EditScriptCmd::desc(); + ss << "]\n" << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()); throw std::runtime_error(ss.str()); } @@ -409,7 +412,7 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& else { throw std::runtime_error( MESSAGE("When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" - << EditScriptCmd::desc())); + << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); } } @@ -426,7 +429,7 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& if ((create_alias || !run_alias) && edit_type != EditScriptCmd::SUBMIT_USER_FILE) { throw std::runtime_error( MESSAGE("The create_alias option is only valid when the second argument is 'submit_file' \n" - << EditScriptCmd::desc())); + << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); } if (args.size() >= 3 && args.size() <= 5) { @@ -468,7 +471,8 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } } - throw std::runtime_error(MESSAGE("Wrong number of arguments specified\n" << EditScriptCmd::desc())); + throw std::runtime_error(MESSAGE("Wrong number of arguments specified\n" + << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); } std::ostream& operator<<(std::ostream& os, const EditScriptCmd& c) { diff --git a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp index cba96f4a3..a95a0ae18 100644 --- a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/core/Converter.hpp" #include "ecflow/core/Extract.hpp" @@ -254,7 +255,7 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A if (args.size() < 2) { throw std::runtime_error(MESSAGE("ForceCmd: At least two arguments expected for Force. Found " << args.size() << "\n" - << ForceCmd::desc() << "\n")); + << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) << "\n")); } std::vector options, paths; @@ -262,13 +263,13 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A args, options, paths, true /*treat_colon_in_path_as_path*/); // relative order is still preserved if (paths.empty()) { throw std::runtime_error(MESSAGE("ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" - << ForceCmd::desc() << "\n")); + << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) << "\n")); } if (options.empty()) { throw std::runtime_error( MESSAGE("ForceCmd: Invalid argument list. Expected of:\n" << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" - << ForceCmd::desc() << "\n")); + << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) << "\n")); } bool is_valid_state = false; @@ -293,7 +294,9 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A stateOrEvent = options[i]; } else { - throw std::runtime_error(MESSAGE("ForceCmd: Invalid argument \n" << ForceCmd::desc() << "\n")); + throw std::runtime_error(MESSAGE("ForceCmd: Invalid argument \n" + << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) + << "\n")); } } diff --git a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp index 8cfdfa114..9c0b3aa11 100644 --- a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/core/Log.hpp" #include "ecflow/node/Node.hpp" @@ -148,7 +149,8 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, if (args.size() < 1) { throw std::runtime_error(MESSAGE("FreeDepCmd: At least one arguments expected for Free dependencies. Found " << args.size() << "\n" - << FreeDepCmd::desc() << "\n")); + << HelpCatalog::description_for("free-dep").value_or(FreeDepCmd::desc()) + << "\n")); } std::vector options, paths; @@ -156,7 +158,7 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, if (paths.empty()) { throw std::runtime_error( MESSAGE("FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" - << FreeDepCmd::desc() << "\n")); + << HelpCatalog::description_for("free-dep").value_or(FreeDepCmd::desc()) << "\n")); } bool trigger = options.empty(); // If no options default to freeing trigger dependencies @@ -178,8 +180,10 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, time = true; } else { - throw std::runtime_error(MESSAGE("FreeDepCmd: Invalid argument(" << options[i] << ")\n" - << FreeDepCmd::desc() << "\n")); + throw std::runtime_error(MESSAGE("FreeDepCmd: Invalid argument(" + << options[i] << ")\n" + << HelpCatalog::description_for("free-dep").value_or(FreeDepCmd::desc()) + << "\n")); } } assert(trigger || all || date || time); // at least one must be true diff --git a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp index 5b62056c3..610948bec 100644 --- a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Filesystem.hpp" @@ -45,7 +46,7 @@ LoadDefsCmd::LoadDefsCmd(const std::string& defs_filename, if (defs_filename_.empty()) { throw std::runtime_error( MESSAGE("LoadDefsCmd::LoadDefsCmd: The pathname to the definition file must be provided\n" - << LoadDefsCmd::desc())); + << HelpCatalog::description_for("load").value_or(LoadDefsCmd::desc()))); } defs_ptr defs = Defs::create(); diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp index 95c439b44..f16310134 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Converter.hpp" @@ -299,7 +300,8 @@ void LogCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, Abs return; } - throw std::runtime_error(MESSAGE("LogCmd: The arguments have not been specified correctly\n" << LogCmd::desc())); + throw std::runtime_error(MESSAGE("LogCmd: The arguments have not been specified correctly\n" + << HelpCatalog::description_for("log").value_or(LogCmd::desc()))); } std::ostream& operator<<(std::ostream& os, const LogCmd& c) { diff --git a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp index d4cc7dfbc..6074374da 100644 --- a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp @@ -17,6 +17,7 @@ #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" #include "ecflow/base/Client.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/cts/user/MoveCmd.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" @@ -304,8 +305,9 @@ void PlugCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, Ab } if (args.size() != 2) { - throw std::runtime_error(MESSAGE("PlugCmd: Two arguments are expected, found " << args.size() << "\n" - << PlugCmd::desc() << "\n")); + throw std::runtime_error(MESSAGE("PlugCmd: Two arguments are expected, found " + << args.size() << "\n" + << HelpCatalog::description_for("plug").value_or(PlugCmd::desc()) << "\n")); } std::string sourceNode = args[0]; diff --git a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp index 17922afa8..37816624f 100644 --- a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp @@ -17,6 +17,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Converter.hpp" @@ -111,7 +112,7 @@ void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A if (attribute.empty()) { throw std::runtime_error(MESSAGE("QueryCmd: no attribute specified: query type: " << query_type << " path+attribute: " << path_and_name << "\n" - << QueryCmd::desc())); + << HelpCatalog::description_for("query").value_or(QueryCmd::desc()))); } } else if (query_type == "trigger") { @@ -126,7 +127,7 @@ void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A } if (attribute.empty()) { throw std::runtime_error(MESSAGE("QueryCmd: no attribute specified: query type: trigger\n" - << QueryCmd::desc())); + << HelpCatalog::description_for("query").value_or(QueryCmd::desc()))); } } else if (query_type == "state" || query_type == "dstate") { diff --git a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp index ba40b3e1f..76bd52901 100644 --- a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Log.hpp" @@ -228,7 +229,7 @@ void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& throw std::runtime_error(MESSAGE( "RequeueNodeCmd: No paths specified. At least one path expected. Paths must begin with a leading '/' " "character\n" - << RequeueNodeCmd::desc() << "\n")); + << HelpCatalog::description_for("requeue").value_or(RequeueNodeCmd::desc()) << "\n")); } RequeueNodeCmd::Option option = RequeueNodeCmd::NO_OPTION; @@ -248,12 +249,14 @@ void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } else { throw std::runtime_error(MESSAGE("RequeueNodeCmd: RequeueNodeCmd: Expected : [force | abort ] paths.\n" - << RequeueNodeCmd::desc() << "\n")); + << HelpCatalog::description_for("requeue").value_or(RequeueNodeCmd::desc()) + << "\n")); } } if (options.size() > 1) { throw std::runtime_error(MESSAGE("RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" - << RequeueNodeCmd::desc() << "\n")); + << HelpCatalog::description_for("requeue").value_or(RequeueNodeCmd::desc()) + << "\n")); } cmd = std::make_shared(paths, option); diff --git a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp index cfc9966b3..14fbf52e0 100644 --- a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp @@ -16,6 +16,7 @@ #include "ecflow/base/AbstractServer.hpp" #include "ecflow/base/AuthenticationDetails.hpp" #include "ecflow/base/AuthorisationDetails.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/base/cts/user/CtsApi.hpp" #include "ecflow/base/stc/PreAllocatedReply.hpp" #include "ecflow/core/Log.hpp" @@ -167,20 +168,23 @@ void RunNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, if (paths.empty()) { throw std::runtime_error( MESSAGE("RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" - << RunNodeCmd::desc() << "\n")); + << HelpCatalog::description_for("run").value_or(RunNodeCmd::desc()) << "\n")); } bool force = false; if (!options.empty()) { if (options.size() != 1) { throw std::runtime_error(MESSAGE("RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" - << RunNodeCmd::desc() << "\n")); + << HelpCatalog::description_for("run").value_or(RunNodeCmd::desc()) + << "\n")); } if (options[0].find("force") != std::string::npos) { force = true; } else { - throw std::runtime_error(MESSAGE("RunNodeCmd: Expected force \n" << RunNodeCmd::desc() << "\n")); + throw std::runtime_error(MESSAGE("RunNodeCmd: Expected force \n" + << HelpCatalog::description_for("run").value_or(RunNodeCmd::desc()) + << "\n")); } } cmd = std::make_shared(paths, force); From ed133915eb5e8cfc377588e221c6608780d98db5 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 16:56:53 +0100 Subject: [PATCH 30/49] Render CLI docs directly from the help manifest build.py generated docs/client_api's index/table/per-command pages by subprocess-invoking the built ecflow_client and scraping its terminal output. This tied doc generation to a full C++ build and let content drift from the manifest whenever it changed without a regeneration. --- docs/client_api/build.py | 160 ++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 54 deletions(-) diff --git a/docs/client_api/build.py b/docs/client_api/build.py index b74f30fc6..5e2c404cf 100755 --- a/docs/client_api/build.py +++ b/docs/client_api/build.py @@ -1,10 +1,21 @@ #!/usr/bin/env python3 -import os -import re import pathlib -import subprocess +import sys -cmd_type_terms = {"child": "child command", "user": "user command", "option": ""} +HERE = pathlib.Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) + +from validate_help_manifest import check_cross_references, check_schema, load_json # noqa: E402 + +cmd_type_terms = {"task": "child command", "user": "user command"} + +# Mirrors Help.cpp's CommandFilter::known_options exactly: the set of names for which +# show_command_help() suppresses the environment-variable banner. This disagrees with the +# manifest's own options[] array in both directions ('help'/'version'/'remove' are manifest +# options but are absent here, so they still get the banner; there is no equivalent entry for +# every manifest option) -- a pre-existing Help.cpp quirk tracked as Future Work, not something +# for build.py to paper over. +KNOWN_OPTIONS = {"add", "debug", "host", "password", "port", "rid", "ssl", "user", "http", "https"} # Maps each ecflow_client command name to the C++ command class section (anchor) that documents its # wire-level protocol in command_internals.rst. Several classes implement many command-line options, so the @@ -100,12 +111,6 @@ } -def run_command(cmd): - print(f"*** Executing: {cmd}") - p = subprocess.run(cmd, capture_output=True, text=True) - return p.stdout, p.stderr - - class Entry: def __init__(self, name, type, desc): self.name = name @@ -116,24 +121,38 @@ def __repr__(self): return f"Entry('{self.name}', '{self.type}', '{self.desc}')" -def load_help_table(command): - entries = [] - o, _ = run_command(command) - o = o.split("\n") - for line in o: - m = re.search(r"""(\S+)\s+(child|user|option)\s+(.*)""", line) - if m and m.groups and len(m.groups()) == 3: - entry = Entry(m.group(1), m.group(2), m.group(3)) - entries.append(entry) - return entries +def load_manifest(): + manifest = load_json(HERE / "help.json") + schema = load_json(HERE / "help.schema.json") + schema_errors = check_schema(manifest, schema) + if schema_errors: + for error in schema_errors: + location = "/".join(str(part) for part in error.path) or "" + print(f"help.json: {location}: {error.message}", file=sys.stderr) + sys.exit(f"{len(schema_errors)} schema violation(s) found in help.json; aborting docs build.") -def load_commands(): - return load_help_table(["ecflow_client", "--help=summary"]) + reference_problems = check_cross_references(manifest) + if reference_problems: + for problem in reference_problems: + print(f"help.json: {problem}", file=sys.stderr) + sys.exit(f"{len(reference_problems)} cross-reference problem(s) found in help.json; aborting docs build.") + return manifest -def load_options(): - return load_help_table(["ecflow_client", "--help=option"]) + +def load_commands(manifest): + # 'internal' commands (e.g. move, constructed on the fly by PlugCmd) are never registered in + # CtsCmdRegistry and have no CLI-reachable --help output; they are intentionally undocumented, + # matching today's behaviour. + visible = [command for command in manifest["commands"] if command["visibility"] != "internal"] + entries = [Entry(command["name"], command["kind"], command["summary"]) for command in visible] + return sorted(entries, key=lambda entry: entry.name) + + +def load_options(manifest): + entries = [Entry(option["name"], option["kind"], option["summary"]) for option in manifest["options"]] + return sorted(entries, key=lambda entry: entry.name) def load_description_file(name): @@ -147,13 +166,68 @@ def load_description_file(name): return f"" -def render_single_page_rst(name): +def join_description(blocks): + # Reproduces HelpCatalog::description_for(): blocks are joined by a blank line, the same rule + # used to originally split the C++ source's paragraphs, including for pre-formatted content. + return "\n\n".join(blocks) + + +def format_env_var(var): + required = var["required"] + if var.get("overridable_by"): + required += "*" + return f" {var['name']} <{var['type']}> [{required}]\n {var['description']}\n" + + +def render_client_env_description(env_vars): + txt = "The client considers, for both user and child commands, the following environment variables:\n\n" + for var in env_vars: + if var["applies_to"] == "both": + txt += format_env_var(var) + txt += ( + "\nThe options marked with (*) must be specified in order for the client to communicate\n" + "with the server, either by setting the environment variables or by specifying the\n" + "command line options.\n" + ) + return txt + + +def render_task_env_description(env_vars): + txt = "The following environment variables are used specifically by child commands:\n\n" + for var in env_vars: + if var["applies_to"] == "task": + txt += format_env_var(var) + txt += "\nThe scripts are expected to export the mandatory variables, typically in shared include files\n" + return txt + + +def render_help_output(manifest, name): + # Reproduces Documentation::show_command_help()'s output byte-for-byte, without invoking the + # built ecflow_client binary: the name banner, the manifest description, and (for anything other + # than an option) the environment-variable sections that show_command_help() appends. + commands_by_name = {command["name"]: command for command in manifest["commands"]} + options_by_name = {option["name"]: option for option in manifest["options"]} + + entry = commands_by_name.get(name) or options_by_name[name] + is_option = name in KNOWN_OPTIONS + is_task_command = name in commands_by_name and commands_by_name[name]["kind"] == "task" + + description = join_description(entry["description"]) + txt = f"\n{name}\n{'-' * len(name)}\n\n{description}\n\n" + if not is_option: + txt += render_client_env_description(manifest["environment_variables"]) + if is_task_command: + txt += "\n" + render_task_env_description(manifest["environment_variables"]) + return txt + + +def render_single_page_rst(manifest, name): description = load_description_file(name) description_title = "Description" description_header = "" if not description else f"\n.. rubric:: {description_title}\n\n" - output, _ = run_command(["ecflow_client", f"--help={name}"]) + output = render_help_output(manifest, name) output = '\n'.join([' ' + line for line in output.split('\n')]) + '\n' # prefix each line of the output with the necessary indentation output_title = f"Output of :code:`--help={name}`" output_header = f"\n.. rubric:: {output_title}\n\n" @@ -191,27 +265,6 @@ def render_single_page_rst(name): return txt -def render_user_option_rst(): - title = f"user" - txt = f""" -.. _user_cli: - -{title} -{"/" * len(title)} - -:: - - - user - ---- - - Specifies the user name used to contact the server. Must be used in combination with option --password. - - -""" - return txt - - def render_index_rst(): title = "Command line interface (CLI)" txt = f""" @@ -337,16 +390,18 @@ def render_options_rst(entries): if __name__ == "__main__": + manifest = load_manifest() + # Render and store index.rst content = render_index_rst() with open("index.rst", "w") as f: f.write(content) - command_entries = load_commands() + command_entries = load_commands(manifest) with open("cli_commands.rst", "w") as f: f.write(render_commands_rst(command_entries)) - option_entries = load_options() + option_entries = load_options(manifest) with open("cli_options.rst", "w") as f: f.write(render_options_rst(option_entries)) @@ -355,14 +410,11 @@ def render_options_rst(entries): # Render and store each of the command/option.rst for entry in command_entries: - content = render_single_page_rst(entry.name) + content = render_single_page_rst(manifest, entry.name) with open(f"api/{entry.name}.rst", "w") as f: f.write(content) for entry in option_entries: - if entry.name == "user": - content = render_user_option_rst() - else: - content = render_single_page_rst(entry.name) + content = render_single_page_rst(manifest, entry.name) with open(f"api/{entry.name}.rst", "w") as f: f.write(content) From 0f6d79a3a66806de6587be65e27abc420fc513b1 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 17:18:42 +0100 Subject: [PATCH 31/49] Drop ecflow_client build dependency from doc generation build.py no longer subprocess-invokes ecflow_client; it renders CLI docs directly from help.json. The DEPENDS ecflow_client line and the PATH-prepend that let build.py find the built binary are both dead weight now, and worse, they mean the docs target only regenerates when the client happens to rebuild, not when the manifest itself changes. Replace that dependency with the manifest, schema, validator script, and build.py itself, so ecflow_client_docs regenerates exactly when its real inputs change and no longer requires a full client build. --- docs/CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index c27b9a3c1..9d4ef82ba 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -54,8 +54,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_CURRENT_SOURCE_DIR}/client_api/api/* COMMAND - ${CMAKE_COMMAND} -E env "PATH=${CMAKE_BINARY_DIR}/bin:$ENV{PATH}" - ${CMAKE_CURRENT_SOURCE_DIR}/client_api/build.py + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/build.py COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/client_api/api @@ -74,7 +73,11 @@ add_custom_command( ${CMAKE_CURRENT_SOURCE_DIR}/client_api WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/client_api USES_TERMINAL - DEPENDS ecflow_client + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/build.py + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/help.json + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/help.schema.json + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/validate_help_manifest.py ) add_custom_target(ecflow_client_docs DEPENDS generate_ecflow_client_docs ecflow_client_help_validate) From 71fee45ababe7fd67206aba3dd5864de0279efcb Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 18:29:39 +0100 Subject: [PATCH 32/49] Route --help=all through the help manifest exclusively Documentation::show_list_options() (backs --help=all) streamed the raw boost::program_options::options_description object directly, bypassing HelpCatalog entirely and rendering every option's Boost-registered literal regardless of manifest migration status - the last rendering path standing between the manifest and being the sole source of command/option documentation. Replace it with a plain per-option listing: a "Client options:" header with the client version, then each option's name and description indented for readability - sourced exclusively from HelpCatalog::description_for(). --- libs/client/src/ecflow/client/Help.cpp | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 38e847a7f..8276c5f50 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -308,7 +308,32 @@ void Documentation::show_help(std::ostream& os) const { } void Documentation::show_list_options(std::ostream& os) const { - os << descriptions_ << "\n"; + // The options are shown using a very plain list of all the options, with their description. + + os << "\n Client options:\n\n " << ecf::Version::description() << "\n\n"; + + for (const auto& option : descriptions_.options()) { + std::string description; + if (std::optional text = ecf::HelpCatalog::description_for(option->long_name())) { + description = *text; + } + else { + description = "No description was found for this option.\n" + "Please report this issue to the development team."; + } + + os << " --" << option->long_name() << "\n\n"; + + std::vector lines; + ecf::algorithm::split_fields_at(lines, description, "\n"); + for (const auto& line : lines) { + if (!line.empty()) { + os << " " << line; + } + os << "\n"; + } + os << "\n"; + } } template From d698b8f425f9b00d25603b9a0d73e39e22502183 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 18:41:24 +0100 Subject: [PATCH 33/49] Eradicate remaining reads of Boost's option description text Replace every fallback with a fixed "Description not provided for this option" message, so nothing in the codebase reads Boost's registered description text anymore, only ecflow_client's own addOption() registration (Boost's API requires the text to be handed over eagerly there, and it is never read back for rendering). --- Viewer/ecflowUI/src/CommandDesignerWidget.cpp | 16 ++++++++-------- libs/client/src/ecflow/client/Help.cpp | 9 ++------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Viewer/ecflowUI/src/CommandDesignerWidget.cpp b/Viewer/ecflowUI/src/CommandDesignerWidget.cpp index 05a7cd350..04ded3a7d 100644 --- a/Viewer/ecflowUI/src/CommandDesignerWidget.cpp +++ b/Viewer/ecflowUI/src/CommandDesignerWidget.cpp @@ -15,6 +15,7 @@ #include "CustomCommandHandler.hpp" #include "NodeExpression.hpp" #include "NodeQueryResult.hpp" +#include "ecflow/base/HelpCatalog.hpp" #include "ecflow/core/Child.hpp" #include "ecflow/core/Str.hpp" @@ -228,16 +229,15 @@ void CommandDesignerWidget::showCommandHelp(QListWidgetItem* item, bool showFull ); if (od) { - // get the description, but only take the first line - std::vector lines; - ecf::algorithm::split_at(lines, od->description(), "\n"); - if (!lines.empty()) { - QString text = qCommand + QString(": "); - commandHelpLabel_->setText(text + QString::fromStdString(lines[0])); - } + std::string summary = + ecf::HelpCatalog::summary_for(od->long_name()).value_or("Description not provided for this option"); + QString text = qCommand + QString(": "); + commandHelpLabel_->setText(text + QString::fromStdString(summary)); if (showFullHelp) { - commandManPage_->setText(qCommand + "\n\n" + QString::fromStdString(od->description())); + std::string description = + ecf::HelpCatalog::description_for(od->long_name()).value_or("Description not provided for this option"); + commandManPage_->setText(qCommand + "\n\n" + QString::fromStdString(description)); } } else { diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 8276c5f50..761bcf90b 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -378,12 +378,7 @@ void Documentation::show_summary(std::ostream& os, PREDICATE select) const { first_line = *summary; } else { - std::vector lines; - ecf::algorithm::split_at(lines, option->description(), "\n"); - if (lines.empty()) { - continue; - } - first_line = lines[0]; + first_line = "Description not provided for this option"; } os << " " << std::left << std::setw(max_width) << name << " "; @@ -432,7 +427,7 @@ void Documentation::show_command_help(std::ostream& os, const std::string& comma os << *text << "\n\n"; } else { - os << od->description() << "\n\n"; + os << "Description not provided for this option" << "\n\n"; } if (!CommandFilter::is_option(od->long_name())) { os << client_env_description; From e8889c476b170e9ca71cd70cc8fcc0d0336bd6f2 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 19:23:31 +0100 Subject: [PATCH 34/49] Stop registering unused descriptions with Boost's option parser Every addOption() implementation still passed a description string to boost::program_options::add_options(), even though nothing reads option_description::description() back anymore - the last two rendering paths (show_summary()'s and show_command_help()'s Boost fallback) were replaced with a fixed warning message, and CLI help now comes exclusively from the JSON manifest via HelpCatalog. Drop the description argument from every 3-arg add_options() call (value-taking options), keeping only the name and value-semantic. For the 22 flag-only options previously registered via the 2-arg (name, description) form - restart, ssl, ping, and 19 others - replace the description text with an empty string, since Boost has no 1-arg overload and building the same untyped_value(true) some other way would risk changing parsing behaviour for zero benefit. Cmd::desc() functions themselves are untouched: they remain the fallback text for the ~29 thrown-parser-error call sites migrated earlier (HelpCatalog::description_for(name).value_or(Cmd::desc())), and Boost's addOption() registration still requires a value-semantic to know each option's shape (single value, multitoken, implicit value) even with no description attached. --- .../src/ecflow/base/cts/CtsCmdRegistry.cpp | 9 +- .../src/ecflow/base/cts/task/AbortCmd.cpp | 3 +- .../src/ecflow/base/cts/task/CompleteCmd.cpp | 6 +- .../src/ecflow/base/cts/task/CtsWaitCmd.cpp | 2 +- .../src/ecflow/base/cts/task/EventCmd.cpp | 3 +- .../base/src/ecflow/base/cts/task/InitCmd.cpp | 6 +- .../src/ecflow/base/cts/task/LabelCmd.cpp | 3 +- .../src/ecflow/base/cts/task/MeterCmd.cpp | 3 +- .../src/ecflow/base/cts/task/QueueCmd.cpp | 3 +- .../src/ecflow/base/cts/user/AlterCmd.cpp | 2 +- .../src/ecflow/base/cts/user/BeginCmd.cpp | 3 +- .../src/ecflow/base/cts/user/CFileCmd.cpp | 3 +- .../src/ecflow/base/cts/user/CSyncCmd.cpp | 37 +-- .../src/ecflow/base/cts/user/CheckPtCmd.cpp | 3 +- .../ecflow/base/cts/user/ClientHandleCmd.cpp | 87 +------ libs/base/src/ecflow/base/cts/user/CtsCmd.cpp | 226 ++---------------- .../src/ecflow/base/cts/user/CtsNodeCmd.cpp | 18 +- .../src/ecflow/base/cts/user/DeleteCmd.cpp | 3 +- .../ecflow/base/cts/user/EditScriptCmd.cpp | 4 +- .../src/ecflow/base/cts/user/ForceCmd.cpp | 3 +- .../src/ecflow/base/cts/user/FreeDepCmd.cpp | 3 +- .../src/ecflow/base/cts/user/GroupCTSCmd.cpp | 2 +- .../src/ecflow/base/cts/user/LoadDefsCmd.cpp | 4 +- libs/base/src/ecflow/base/cts/user/LogCmd.cpp | 3 +- .../ecflow/base/cts/user/LogMessageCmd.cpp | 2 +- .../base/src/ecflow/base/cts/user/MoveCmd.cpp | 3 +- .../src/ecflow/base/cts/user/OrderNodeCmd.cpp | 4 +- .../src/ecflow/base/cts/user/PathsCmd.cpp | 25 +- .../base/src/ecflow/base/cts/user/PlugCmd.cpp | 3 +- .../src/ecflow/base/cts/user/QueryCmd.cpp | 3 +- .../ecflow/base/cts/user/ReplaceNodeCmd.cpp | 4 +- .../ecflow/base/cts/user/RequeueNodeCmd.cpp | 4 +- .../src/ecflow/base/cts/user/RunNodeCmd.cpp | 3 +- .../ecflow/base/cts/user/ServerVersionCmd.cpp | 2 +- .../base/src/ecflow/base/cts/user/ShowCmd.cpp | 3 +- .../src/ecflow/base/cts/user/ZombieCmd.cpp | 61 +---- .../src/ecflow/client/ClientOptions.cpp | 38 +-- 37 files changed, 97 insertions(+), 497 deletions(-) diff --git a/libs/base/src/ecflow/base/cts/CtsCmdRegistry.cpp b/libs/base/src/ecflow/base/cts/CtsCmdRegistry.cpp index 49d27f15b..5dbd7df69 100644 --- a/libs/base/src/ecflow/base/cts/CtsCmdRegistry.cpp +++ b/libs/base/src/ecflow/base/cts/CtsCmdRegistry.cpp @@ -178,10 +178,7 @@ void CtsCmdRegistry::addCmdOptions(boost::program_options::options_description& void CtsCmdRegistry::addHelpOption(boost::program_options::options_description& desc) const { /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - desc.add_options()( - "help,h", boost::program_options::value()->implicit_value(std::string{}), "Produce help message"); - desc.add_options()("version,v", "Show ecflow client version number, and version of the boost library used"); - desc.add_options()("debug,d", - "Enables the display of client environment settings and execution details.\n" - "Has the same effect as setting environment variable ECF_DEBUG_CLIENT."); + desc.add_options()("help,h", boost::program_options::value()->implicit_value(std::string{})); + desc.add_options()("version,v", ""); + desc.add_options()("debug,d", ""); } diff --git a/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp b/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp index e127324b7..eb4cab367 100644 --- a/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp @@ -111,8 +111,7 @@ const char* AbortCmd::desc() { } void AbortCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - AbortCmd::arg(), boost::program_options::value()->implicit_value(std::string{}), AbortCmd::desc()); + desc.add_options()(AbortCmd::arg(), boost::program_options::value()->implicit_value(std::string{})); } void AbortCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { std::string reason = vm[arg()].as(); diff --git a/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp b/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp index cb0adb666..ad5ffaf50 100644 --- a/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp @@ -97,10 +97,8 @@ const char* CompleteCmd::desc() { } void CompleteCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(CompleteCmd::arg(), - CompleteCmd::desc())("remove", - boost::program_options::value>()->multitoken(), - "remove variables i.e name name2"); + desc.add_options()(CompleteCmd::arg(), "")("remove", + boost::program_options::value>()->multitoken()); } void CompleteCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { if (clientEnv->debug()) { diff --git a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp index 054c9eace..01c92fc0a 100644 --- a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp @@ -112,7 +112,7 @@ const char* CtsWaitCmd::desc() { } void CtsWaitCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(CtsWaitCmd::arg(), boost::program_options::value(), CtsWaitCmd::desc()); + desc.add_options()(CtsWaitCmd::arg(), boost::program_options::value()); } void CtsWaitCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { std::string expression = vm[arg()].as(); diff --git a/libs/base/src/ecflow/base/cts/task/EventCmd.cpp b/libs/base/src/ecflow/base/cts/task/EventCmd.cpp index dce9c21f9..e4a94dab5 100644 --- a/libs/base/src/ecflow/base/cts/task/EventCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/EventCmd.cpp @@ -102,8 +102,7 @@ const char* EventCmd::desc() { } void EventCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - EventCmd::arg(), boost::program_options::value>()->multitoken(), EventCmd::desc()); + desc.add_options()(EventCmd::arg(), boost::program_options::value>()->multitoken()); } void EventCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/task/InitCmd.cpp b/libs/base/src/ecflow/base/cts/task/InitCmd.cpp index a28d368b5..fec798180 100644 --- a/libs/base/src/ecflow/base/cts/task/InitCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/InitCmd.cpp @@ -95,10 +95,8 @@ const char* InitCmd::desc() { } void InitCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(InitCmd::arg(), boost::program_options::value(), InitCmd::desc())( - "add", - boost::program_options::value>()->multitoken(), - "Add variables e.g. name1=value1 name2=value2. Can only be used in combination with --init command."); + desc.add_options()(InitCmd::arg(), boost::program_options::value())( + "add", boost::program_options::value>()->multitoken()); } void InitCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { diff --git a/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp b/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp index bc0a34849..6b154bb53 100644 --- a/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp @@ -97,8 +97,7 @@ const char* LabelCmd::desc() { } void LabelCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - LabelCmd::arg(), boost::program_options::value>()->multitoken(), LabelCmd::desc()); + desc.add_options()(LabelCmd::arg(), boost::program_options::value>()->multitoken()); } void LabelCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp b/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp index 7d8fff5cc..eed87883f 100644 --- a/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp @@ -113,8 +113,7 @@ const char* MeterCmd::desc() { } void MeterCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - MeterCmd::arg(), boost::program_options::value>()->multitoken(), MeterCmd::desc()); + desc.add_options()(MeterCmd::arg(), boost::program_options::value>()->multitoken()); } void MeterCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp b/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp index ec5674adc..d87861f5d 100644 --- a/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp @@ -205,8 +205,7 @@ const char* QueueCmd::desc() { } void QueueCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - QueueCmd::arg(), boost::program_options::value>()->multitoken(), QueueCmd::desc()); + desc.add_options()(QueueCmd::arg(), boost::program_options::value>()->multitoken()); } void QueueCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp index b2f9324a3..bc4739c12 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -733,7 +733,7 @@ void AlterCmd::addOption(boost::program_options::options_description& desc) cons // po::value>()->multitoken()). However, because of the special handling // necessary to allow positional values, such as "--help", a custom `style_parser` is used // instead when parsing the CLI options -- see ClientOptions for details. - desc.add_options()(AlterCmd::arg(), boost::program_options::value>(), AlterCmd::desc()); + desc.add_options()(AlterCmd::arg(), boost::program_options::value>()); } void AlterCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp index 4430110f7..127e0173c 100644 --- a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp @@ -148,8 +148,7 @@ void BeginCmd::addOption(boost::program_options::options_description& desc) cons // allow options like // client --begin=suitename // begin // client --begin // means begin all suites - desc.add_options()( - BeginCmd::arg(), boost::program_options::value()->implicit_value(std::string{}), BeginCmd::desc()); + desc.add_options()(BeginCmd::arg(), boost::program_options::value()->implicit_value(std::string{})); } void BeginCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ace) const { std::string beginArg = vm[arg()].as(); diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp index 8aab6ace7..6da60a97d 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp @@ -346,8 +346,7 @@ const char* CFileCmd::desc() { } void CFileCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - CFileCmd::arg(), boost::program_options::value>()->multitoken(), CFileCmd::desc()); + desc.add_options()(CFileCmd::arg(), boost::program_options::value>()->multitoken()); } void CFileCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/CSyncCmd.cpp b/libs/base/src/ecflow/base/cts/user/CSyncCmd.cpp index 452a66a77..1c3e1cf32 100644 --- a/libs/base/src/ecflow/base/cts/user/CSyncCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CSyncCmd.cpp @@ -170,49 +170,22 @@ STC_Cmd_ptr CSyncCmd::doHandleRequest(AbstractServer* as) const { void CSyncCmd::addOption(boost::program_options::options_description& desc) const { if (api_ == CSyncCmd::NEWS) { - desc.add_options()( - CtsApi::newsArg(), - boost::program_options::value>()->multitoken(), - "Returns true if state of server definition changed.\n" - "*Important* for use with c++/python interface only.\n" - "Requires Given a client handle, change and modify number determine if server changed since last call\n" - "This relies on user calling sync after news to update the locally stored modify and change numbers.\n" - "These numbers are then used in the next call to news."); + desc.add_options()(CtsApi::newsArg(), boost::program_options::value>()->multitoken()); return; } if (api_ == CSyncCmd::SYNC) { - desc.add_options()( - CtsApi::syncArg(), - boost::program_options::value>()->multitoken(), - "Incrementally synchronise the local definition with the one in the server.\n" - "*Important* for use with c++/python interface only.\n" - "Preference should be given to this method as only the changes are returned.\n" - "This reduces the network bandwidth required to keep in sync with the server\n" - "Requires a client handle, change and modify number, to get the incremental changes from server.\n" - "The change in server state is then and merged with the client definition."); + desc.add_options()(CtsApi::syncArg(), boost::program_options::value>()->multitoken()); return; } if (api_ == CSyncCmd::SYNC_CLOCK) { - desc.add_options()( - CtsApi::sync_clock_arg(), - boost::program_options::value>()->multitoken(), - "Incrementally synchronise the local definition with the one in the server.\n" - "*Important* for use with c++/python interface only.\n" - "Same as sync, but will *always* sync with suite clock if it has changed.\n" - "Preference should be given to this method as only the changes are returned.\n" - "This reduces the network bandwidth required to keep in sync with the server\n" - "Requires a client handle, change and modify number, to get the incremental changes from server.\n" - "The change in server state is then and merged with the client definition."); + desc.add_options()(CtsApi::sync_clock_arg(), + boost::program_options::value>()->multitoken()); return; } - desc.add_options()(CtsApi::sync_full_arg(), - boost::program_options::value(), - "Returns the full definition from the server.\n" - "*Important* for use with c++/python interface only.\n" - "Requires a client_handle. The returned definition is stored on the client."); + desc.add_options()(CtsApi::sync_full_arg(), boost::program_options::value()); } void CSyncCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { diff --git a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp index 025eb39c4..694111074 100644 --- a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp @@ -132,8 +132,7 @@ static const char* arg_desc() { void CheckPtCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CtsApi::checkPtDefsArg(), - boost::program_options::value()->implicit_value(std::string{}), - arg_desc()); + boost::program_options::value()->implicit_value(std::string{})); } static int parse_check_pt_interval(const std::string& the_arg) { diff --git a/libs/base/src/ecflow/base/cts/user/ClientHandleCmd.cpp b/libs/base/src/ecflow/base/cts/user/ClientHandleCmd.cpp index 46bf4a6df..838176137 100644 --- a/libs/base/src/ecflow/base/cts/user/ClientHandleCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ClientHandleCmd.cpp @@ -262,109 +262,42 @@ void ClientHandleCmd::addOption(boost::program_options::options_description& des switch (api_) { case ClientHandleCmd::REGISTER: { - desc.add_options()( - CtsApi::ch_register_arg(), - boost::program_options::value>()->multitoken(), - "Register interest in a set of suites.\n" - "If a definition has lots of suites, but the client. is only interested in a small subset,\n" - "Then using this command can reduce network bandwidth and synchronisation will be quicker.\n" - "This command will create a client handle, which must be used for any other changes.\n" - "The newly created handle can be shown with the --ch_suites command\n" - "Deleted suites will stay registered, and must be explicitly removed/dropped.\n" - "Note: Suites can be registered before they are loaded into the server\n" - "This command affects news() and sync() commands\n" - " arg1 = true | false # true means add new suites to my list, when they are created\n" - " arg2 = names # should be a list of suite names, names not in the definition are " - "ignored\n" - "Usage:\n" - " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites\n" - " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only\n" - " --ch_register=false # register handle, suites will be added later on\n" - " --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any " - "new suites\n" - " # The client handle as the first argument is typically used by " - "GUI/python" - " # When the client handle is no zero, then it is dropped first\n" - "To list all suites and handles use --ch_suites"); + desc.add_options()(CtsApi::ch_register_arg(), + boost::program_options::value>()->multitoken()); break; } case ClientHandleCmd::DROP: { - desc.add_options()(CtsApi::ch_drop_arg(), - boost::program_options::value(), - "Drop/de-register the client handle.\n" - "Un-used handle should be dropped otherwise they will stay, in the server.\n" - " arg1 = handle(integer) # The handle must be an integer that is > 0\n" - "Usage:\n" - " --ch_drop=10 # drop the client handle 10\n" - "An error is returned if the handle had not previously been registered\n" - "The handle stored on the local client is set to zero\n" - "To list all suites and handles use --ch_suites"); + desc.add_options()(CtsApi::ch_drop_arg(), boost::program_options::value()); break; } case ClientHandleCmd::DROP_USER: { - desc.add_options()( - CtsApi::ch_drop_user_arg(), - boost::program_options::value()->implicit_value(std::string{}), - "Drop/de-register all handles associated with the given user.\n" - "If no user provided will drop for current user. Client must ensure un-used handle are dropped\n" - "otherwise they will stay, in the server.\n" - " arg1 = user # The user to be drooped, if left empty drop current user \n" - "Usage:\n" - " --ch_drop_user=ma0 # drop all handles associated with user ma0\n" - " --ch_drop_user # drop all handles associated with current user\n" - "An error is returned if no registered handles\n" - "To list all suites and handles use --ch_suites"); + desc.add_options()(CtsApi::ch_drop_user_arg(), + boost::program_options::value()->implicit_value(std::string{})); break; } case ClientHandleCmd::ADD: { desc.add_options()(CtsApi::ch_add_arg(), - boost::program_options::value>()->multitoken(), - "Add a set of suites, to an existing handle.\n" - " arg1 = handle(integer) # The handle must be an integer that is > 0\n" - " arg2 = names # should be a list of suite names, names not in the " - "definition are ignored\n" - "Usage:\n" - " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10\n" - "An error is returned if the handle had not previously been registered\n" - "The handle is created with --ch_register command\n" - "To list all suites and handles use --ch_suites"); + boost::program_options::value>()->multitoken()); break; } case ClientHandleCmd::REMOVE: { desc.add_options()(CtsApi::ch_remove_arg(), - boost::program_options::value>()->multitoken(), - "Remove a set of suites, from an existing handle.\n" - " arg1 = handle(integer) # The handle must be an integer that is > 0\n" - " arg2 = names # should be a list of suite names, names not in the " - "definition are ignored\n" - "Usage:\n" - " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10\n" - "The handle is created with --ch_register command\n" - "To list all suites and handles use --ch_suites"); + boost::program_options::value>()->multitoken()); break; } case ClientHandleCmd::AUTO_ADD: { - desc.add_options()( - CtsApi::ch_auto_add_arg(), - boost::program_options::value>()->multitoken(), - "Change an existing handle so that new suites can be added automatically.\n" - " arg1 = handle(integer) # The handle must be an integer that is > 0\n" - " arg2 = true | false # true means add new suites to my list, when they are created\n" - "Usage:\n" - " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it\n" - " --ch_auto_add=10 false # modify handle 10 so that no new suites are added\n" - "The handle is created with --ch_register command\n" - "To list all suites and handles use --ch_suites"); + desc.add_options()(CtsApi::ch_auto_add_arg(), + boost::program_options::value>()->multitoken()); break; } case ClientHandleCmd::SUITES: { - desc.add_options()(CtsApi::ch_suites_arg(), "Shows all the client handles, and the suites they reference"); + desc.add_options()(CtsApi::ch_suites_arg(), ""); break; } default: diff --git a/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp b/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp index 8f5653193..f1b8fb987 100644 --- a/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp @@ -473,270 +473,80 @@ static const char* server_load_desc() { void CtsCmd::addOption(boost::program_options::options_description& desc) const { switch (api_) { case CtsCmd::GET_ZOMBIES: { - desc.add_options()(CtsApi::zombieGetArg(), - "Returns the list of zombies from the server.\n" - "Results reported to standard output."); + desc.add_options()(CtsApi::zombieGetArg(), ""); break; } case CtsCmd::RESTORE_DEFS_FROM_CHECKPT: { - desc.add_options()(CtsApi::restoreDefsFromCheckPtArg(), - "Ask the server to load the definition from an check pt file.\n" - "The server must be halted and the definition in the server must be deleted\n" - "first, otherwise an error is returned"); + desc.add_options()(CtsApi::restoreDefsFromCheckPtArg(), ""); break; } case CtsCmd::RESTART_SERVER: { - desc.add_options()(CtsApi::restartServerArg(), - "Start job scheduling, communication with jobs, and respond to all requests.\n" - "The following table shows server behaviour in the different states.\n" - "|----------------------------------------------------------------------------------|\n" - "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n" - "|--------------|--------------|--------------|---------------|---------------------|\n" - "| RUNNING | yes | yes | yes | yes |\n" - "| SHUTDOWN | yes | yes | no | yes |\n" - "| HALTED | yes | no | no | no |\n" - "|--------------|--------------|--------------|---------------|---------------------|"); + desc.add_options()(CtsApi::restartServerArg(), ""); break; } case CtsCmd::SHUTDOWN_SERVER: { desc.add_options()(CtsApi::shutdownServerArg(), - boost::program_options::value()->implicit_value(std::string{}), - "Stop server from scheduling new jobs.\n" - " arg1 = yes(optional) # use to bypass confirmation prompt,i.e\n" - " --shutdown=yes\n" - "The following table shows server behaviour in the different states.\n" - "|----------------------------------------------------------------------------------|\n" - "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n" - "|--------------|--------------|--------------|---------------|---------------------|\n" - "| RUNNING | yes | yes | yes | yes |\n" - "| SHUTDOWN | yes | yes | no | yes |\n" - "| HALTED | yes | no | no | no |\n" - "|--------------|--------------|--------------|---------------|---------------------|"); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsCmd::HALT_SERVER: { desc.add_options()(CtsApi::haltServerArg(), - boost::program_options::value()->implicit_value(std::string{}), - "Stop server communication with jobs, and new job scheduling.\n" - "Also stops automatic check pointing\n" - " arg1 = yes(optional) # use to bypass confirmation prompt,i.e.\n" - " --halt=yes\n" - "The following table shows server behaviour in the different states.\n" - "|----------------------------------------------------------------------------------|\n" - "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n" - "|--------------|--------------|--------------|---------------|---------------------|\n" - "| RUNNING | yes | yes | yes | yes |\n" - "| SHUTDOWN | yes | yes | no | yes |\n" - "| HALTED | yes | no | no | no |\n" - "|--------------|--------------|--------------|---------------|---------------------|"); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsCmd::TERMINATE_SERVER: { desc.add_options()(CtsApi::terminateServerArg(), - boost::program_options::value()->implicit_value(std::string{}), - "Terminate the server.\n" - " arg1 = yes(optional) # use to bypass confirmation prompt.i.e\n" - " --terminate=yes"); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsCmd::RELOAD_WHITE_LIST_FILE: { - desc.add_options()( - CtsApi::reloadwsfileArg(), - "Reload the white list file.\n" - "\n" - "The white list file (authorisation) is used to verify if a 'user' is allowed to perform a\n" - "specific command.\n" - "\n" - "The file path is specified as the ECF_LISTS variable, and loaded only once by the server\n" - "(on *startup*). This means that the file contents can be updated, but the file location\n" - "cannot change during the server execution.\n" - "\n" - "The ECF_LISTS variable can be used as follows:\n" - " - if ECF_LISTS is not specified, or if it is specified with value `ecf.lists`,\n" - " then the server will use the value `..ecf.lists`\n" - " - if ECF_LISTS is specified to be a path, such as /var/tmp/ecf.lists,\n" - " then the server will use this path to reload the white list file\n" - "\n" - "The server automatically loads the white list file content as part of the startup procedure,\n" - "considering that if the file is not present or is empty (i.e., just contains the version\n" - "number) then all users have read/write access.\n" - "\n" - "The reload operation will fail if file does not exist or if the content is invalid.\n" - "\n" - "Expected format for this file is:\n" - "\n" - "\n" - "# all characters after the first # in a line are considered comments and are discarded\n" - "# empty lines are also discarded\n" - "\n" - "4.4.14 # the version number is mandatory, even if no users are specified\n" - "# Users with read/write access\n" - "user1\n" - "user2 # comment\n" - "* # use this form if you want all users to have read/write access\n" - "\n" - "# Users with read access, must have - before user name\n" - "-user3 # comment\n" - "-user4\n" - "-* # use this form if you want all users to have read access\n" - "\n" - "\n" - "Usage:\n" - " --reloadwsfile"); + desc.add_options()(CtsApi::reloadwsfileArg(), ""); break; } case CtsCmd::RELOAD_PASSWD_FILE: { - desc.add_options()( - CtsApi::reloadpasswdfile_arg(), - "Reload the server password file.\n" - "\n" - "The password file (authentication) is used by the server to authenticate a 'user' by\n" - "verifying if the password provided by the user matches the one held by the server.\n" - "The password file is also used on the client to automatically load the password for the\n" - "'user' when connecting to the server.\n" - "\n" - "When the server is configured to use a password file, then ALL users must have a password.\n" - "\n" - "The file path is specified as the ECF_PASSWD environment variable, both for the client and\n" - "server, and is loaded only by the server on *startup*. This means that the file contents\n" - "can be updated (i.e., add/remove users), but the file location cannot change during the\n" - "server execution.\n" - "\n" - "The server automatically loads the password file content as part of the startup procedure.\n" - "\n" - "The ECF_PASSWD environment variable is used to specify the password file location,\n" - "considering that\n" - " - On the server, the default file name is ..ecf.passwd\n" - " - On the client, the default file name is ecf.passwd\n" - "\n" - "The format of the file is same for client and server:\n" - "\n" - "\n" - "4.5.0\n" - "# comment\n" - " # comment\n" - "\n" - "The following is an example\n" - "\n" - "4.5.0 # the version\n" - "fred machine1 3142 xxyyyd\n" - "fred machine2 3133 xxyyyd # comment\n" - "bill machine2 3133 xxyggyyd\n" - "\n" - "\n" - "Notice that the same user may appear multiple times (associated with different host/port).\n" - "This allows the client to use the same password file to contact multiple servers.\n" - "\n" - "For the password authentication to work, ensure the following:\n" - " - The password is defined for the client and server\n" - " - On the server, add at least the server administrator to the password file\n" - " Note: If an empty password file (i.e., containing just the version) is used,\n" - " no user is allowed access.\n" - " - On the client, the password file should be readable only by the 'user' itself\n" - "\n" - "Usage:\n" - " --reloadpasswdfile"); + desc.add_options()(CtsApi::reloadpasswdfile_arg(), ""); break; } case CtsCmd::RELOAD_CUSTOM_PASSWD_FILE: { - desc.add_options()( - CtsApi::reloadcustompasswdfile_arg(), - "Reload the server custom password file.\n" - "\n" - "The custom password file (authentication) is used by the server to authenticate a 'user' by\n" - "verifying if the password provided by the user matches the one held by the server. This\n" - "particular file is used for authentication of users that explicitly specify the user name\n" - "(either via the environment variable ECF_USER or the --user option).\n" - "\n" - "This mechanism should be used when most users use the machine login name, but a few users\n" - "specify their own user name, in which case the password must also be explicitly provided.\n" - "\n" - "The file path is specified as the ECF_CUSTOM_PASSWD environment variable, both for the\n" - "client and server, and is loaded only by the server on *startup*. This means that the file\n" - "contents can be updated (i.e., add/remove users), but the file location cannot change during\n" - "the server execution.\n" - "\n" - "The server automatically loads the password file content as part of the startup procedure.\n" - "\n" - "The ECF_CUSTOM_PASSWD environment variable is used to specify the password file location,\n" - "considering that\n" - " - On the server the default file name is ..ecf.custom_passwd\n" - " - On the client the default file name is ecf.custom_passwd\n" - "\n" - "The format of the file is same for client and server:\n\n" - "\n" - "4.5.0\n" - "# comment\n" - " # comment\n" - "\n" - "The following is an example\n" - "\n" - "4.5.0 # the version\n" - "fred machine1 3142 xxyyyd\n" - "fred machine2 3133 xxyyyd # comment\n" - "bill machine2 3133 xxyggyyd\n" - "\n" - "Notice that the same user may appear multiple times (associated with different host/port).\n" - "This allows the client to use the same password file to contact multiple servers.\n" - "\n" - "For the password authentication to work, ensure the following:\n" - " - The password is defined for the client and server\n" - " - On the server, add at least the server administrator to the password file\n" - " Note: If an empty password file (i.e., containing just the version) is used,\n" - " no user is allowed access.\n" - " - On the client, the password file should be readable only by the 'user' itself\n" - "\n" - "Usage:\n" - " --reloadcustompasswdfile"); + desc.add_options()(CtsApi::reloadcustompasswdfile_arg(), ""); break; } case CtsCmd::FORCE_DEP_EVAL: { - desc.add_options()(CtsApi::forceDependencyEvalArg(), "Force dependency evaluation. Used for DEBUG only."); + desc.add_options()(CtsApi::forceDependencyEvalArg(), ""); break; } case CtsCmd::PING: { - desc.add_options()( - CtsApi::pingServerArg(), - "Check if server is running on given host/port. Result reported to standard output.\n" - "Usage:\n" - " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144\n" - " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,\n" - " # otherwise default port of 3141\n" - " --ping # Check if server alive by using environment variables\n" - " # ECF_HOST and ECF_PORT\n" - "If ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141"); + desc.add_options()(CtsApi::pingServerArg(), ""); break; } case CtsCmd::STATS: { - desc.add_options()(CtsApi::statsArg(), "Returns the server statistics as a string."); + desc.add_options()(CtsApi::statsArg(), ""); break; } case CtsCmd::STATS_SERVER: { - desc.add_options()(CtsApi::stats_server_arg(), - "Returns the server statistics as a struct and string. For test use only."); + desc.add_options()(CtsApi::stats_server_arg(), ""); break; } case CtsCmd::STATS_RESET: { - desc.add_options()(CtsApi::stats_reset_arg(), "Resets the server statistics."); + desc.add_options()(CtsApi::stats_reset_arg(), ""); break; } case CtsCmd::SUITES: { - desc.add_options()(CtsApi::suitesArg(), "Returns the list of suites, in the order defined in the server."); + desc.add_options()(CtsApi::suitesArg(), ""); break; } case CtsCmd::DEBUG_SERVER_ON: { - desc.add_options()(CtsApi::debug_server_on_arg(), "Enables debug output from the server"); + desc.add_options()(CtsApi::debug_server_on_arg(), ""); break; } case CtsCmd::DEBUG_SERVER_OFF: { - desc.add_options()(CtsApi::debug_server_off_arg(), "Disables debug output from the server"); + desc.add_options()(CtsApi::debug_server_off_arg(), ""); break; } case CtsCmd::SERVER_LOAD: { desc.add_options()(CtsApi::server_load_arg(), - boost::program_options::value()->implicit_value(std::string{}), - server_load_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsCmd::NO_CMD: diff --git a/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp index 84f2eb27b..54f7a01a5 100644 --- a/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp @@ -327,38 +327,32 @@ void CtsNodeCmd::addOption(boost::program_options::options_description& desc) co switch (api_) { case CtsNodeCmd::GET: { desc.add_options()(CtsApi::getArg(), - boost::program_options::value()->implicit_value(std::string{}), - get_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsNodeCmd::GET_STATE: { desc.add_options()(CtsApi::get_state_arg(), - boost::program_options::value()->implicit_value(std::string{}), - get_state_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsNodeCmd::MIGRATE: { desc.add_options()(CtsApi::migrate_arg(), - boost::program_options::value()->implicit_value(std::string{}), - migrate_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsNodeCmd::JOB_GEN: { desc.add_options()(CtsApi::job_genArg(), - boost::program_options::value()->implicit_value(std::string{}), - job_gen_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsNodeCmd::CHECK_JOB_GEN_ONLY: { desc.add_options()(CtsApi::checkJobGenOnlyArg(), - boost::program_options::value()->implicit_value(std::string{}), - job_gen_only_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsNodeCmd::WHY: { desc.add_options()(CtsApi::whyArg(), - boost::program_options::value()->implicit_value(std::string{}), - why_desc()); + boost::program_options::value()->implicit_value(std::string{})); break; } case CtsNodeCmd::NO_CMD: diff --git a/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp b/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp index 7ecd513f9..996390f17 100644 --- a/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp @@ -181,8 +181,7 @@ static const char* delete_node_desc() { void DeleteCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CtsApi::delete_node_arg(), - boost::program_options::value>()->multitoken(), - delete_node_desc()); + boost::program_options::value>()->multitoken()); } void DeleteCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { diff --git a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp index bb7ce23a2..f738f7709 100644 --- a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp @@ -341,9 +341,7 @@ const char* EditScriptCmd::desc() { } void EditScriptCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(EditScriptCmd::arg(), - boost::program_options::value>()->multitoken(), - EditScriptCmd::desc()); + desc.add_options()(EditScriptCmd::arg(), boost::program_options::value>()->multitoken()); } void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { diff --git a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp index a95a0ae18..1c0271f22 100644 --- a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp @@ -242,8 +242,7 @@ const char* ForceCmd::desc() { } void ForceCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - ForceCmd::arg(), boost::program_options::value>()->multitoken(), ForceCmd::desc()); + desc.add_options()(ForceCmd::arg(), boost::program_options::value>()->multitoken()); } void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp index 9c0b3aa11..cd6ccdb9d 100644 --- a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp @@ -136,8 +136,7 @@ const char* FreeDepCmd::desc() { } void FreeDepCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - FreeDepCmd::arg(), boost::program_options::value>()->multitoken(), FreeDepCmd::desc()); + desc.add_options()(FreeDepCmd::arg(), boost::program_options::value>()->multitoken()); } void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { auto args = vm[arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp b/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp index a861d47f1..b0214d497 100644 --- a/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp @@ -400,7 +400,7 @@ const char* GroupCTSCmd::desc() { } void GroupCTSCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(GroupCTSCmd::arg(), boost::program_options::value(), GroupCTSCmd::desc()); + desc.add_options()(GroupCTSCmd::arg(), boost::program_options::value()); } void GroupCTSCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { diff --git a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp index 610948bec..817d9dc1d 100644 --- a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp @@ -184,9 +184,7 @@ const char* LoadDefsCmd::desc() { } void LoadDefsCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(LoadDefsCmd::arg(), - boost::program_options::value>()->multitoken(), - LoadDefsCmd::desc()); + desc.add_options()(LoadDefsCmd::arg(), boost::program_options::value>()->multitoken()); } void LoadDefsCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp index f16310134..3469ab84a 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp @@ -220,8 +220,7 @@ const char* LogCmd::desc() { } void LogCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - LogCmd::arg(), boost::program_options::value>()->multitoken(), LogCmd::desc()); + desc.add_options()(LogCmd::arg(), boost::program_options::value>()->multitoken()); } void LogCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { diff --git a/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp index 33785f4dc..55488e42f 100644 --- a/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp @@ -64,7 +64,7 @@ const char* LogMessageCmd::desc() { } void LogMessageCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(LogMessageCmd::arg(), boost::program_options::value(), LogMessageCmd::desc()); + desc.add_options()(LogMessageCmd::arg(), boost::program_options::value()); } void LogMessageCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ace) const { diff --git a/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp b/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp index e63b09ab5..fdc8f1ec7 100644 --- a/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp @@ -200,8 +200,7 @@ const char* MoveCmd::desc() { } void MoveCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - MoveCmd::arg(), boost::program_options::value>()->multitoken(), MoveCmd::desc()); + desc.add_options()(MoveCmd::arg(), boost::program_options::value>()->multitoken()); } void MoveCmd::create(Cmd_ptr&, boost::program_options::variables_map&, AbstractClientEnv*) const { diff --git a/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp index cb867a096..9cea76ecd 100644 --- a/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp @@ -102,9 +102,7 @@ const char* OrderNodeCmd::desc() { } void OrderNodeCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(OrderNodeCmd::arg(), - boost::program_options::value>()->multitoken(), - OrderNodeCmd::desc()); + desc.add_options()(OrderNodeCmd::arg(), boost::program_options::value>()->multitoken()); } void OrderNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { auto args = vm[OrderNodeCmd::arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp b/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp index f21257383..2d71344d9 100644 --- a/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp @@ -594,44 +594,35 @@ void PathsCmd::addOption(boost::program_options::options_description& desc) cons switch (api_) { case PathsCmd::CHECK: { - desc.add_options()( - CtsApi::check_arg(), po::value>()->multitoken(), get_check_desc()); + desc.add_options()(CtsApi::check_arg(), po::value>()->multitoken()); break; } case PathsCmd::SUSPEND: { - desc.add_options()( - CtsApi::suspend_arg(), po::value>()->multitoken(), suspend_desc()); + desc.add_options()(CtsApi::suspend_arg(), po::value>()->multitoken()); break; } case PathsCmd::RESUME: { - desc.add_options()( - CtsApi::resume_arg(), po::value>()->multitoken(), resume_desc()); + desc.add_options()(CtsApi::resume_arg(), po::value>()->multitoken()); break; } case PathsCmd::KILL: { - desc.add_options()( - CtsApi::kill_arg(), po::value>()->multitoken(), get_kill_desc()); + desc.add_options()(CtsApi::kill_arg(), po::value>()->multitoken()); break; } case PathsCmd::STATUS: { - desc.add_options()( - CtsApi::statusArg(), po::value>()->multitoken(), get_status_desc()); + desc.add_options()(CtsApi::statusArg(), po::value>()->multitoken()); break; } case PathsCmd::EDIT_HISTORY: { - desc.add_options()(CtsApi::edit_history_arg(), - po::value>()->multitoken(), - get_edit_history_desc()); + desc.add_options()(CtsApi::edit_history_arg(), po::value>()->multitoken()); break; } case PathsCmd::ARCHIVE: { - desc.add_options()( - CtsApi::archive_arg(), po::value>()->multitoken(), archive_desc()); + desc.add_options()(CtsApi::archive_arg(), po::value>()->multitoken()); break; } case PathsCmd::RESTORE: { - desc.add_options()( - CtsApi::restore_arg(), po::value>()->multitoken(), restore_desc()); + desc.add_options()(CtsApi::restore_arg(), po::value>()->multitoken()); break; } case PathsCmd::NO_CMD: diff --git a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp index 6074374da..8bda811ae 100644 --- a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp @@ -293,8 +293,7 @@ const char* PlugCmd::desc() { } void PlugCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - PlugCmd::arg(), boost::program_options::value>()->multitoken(), PlugCmd::desc()); + desc.add_options()(PlugCmd::arg(), boost::program_options::value>()->multitoken()); } void PlugCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ace) const { diff --git a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp index 37816624f..844848c0e 100644 --- a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp @@ -72,8 +72,7 @@ ecf::authorisation_t QueryCmd::authorise(AbstractServer& server) const { } void QueryCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - QueryCmd::arg(), boost::program_options::value>()->multitoken(), QueryCmd::desc()); + desc.add_options()(QueryCmd::arg(), boost::program_options::value>()->multitoken()); } void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const { diff --git a/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp index 49df9fd44..a185cfc5b 100644 --- a/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp @@ -211,9 +211,7 @@ const char* ReplaceNodeCmd::desc() { } void ReplaceNodeCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(ReplaceNodeCmd::arg(), - boost::program_options::value>()->multitoken(), - ReplaceNodeCmd::desc()); + desc.add_options()(ReplaceNodeCmd::arg(), boost::program_options::value>()->multitoken()); } void ReplaceNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, diff --git a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp index 76bd52901..4fdadf43d 100644 --- a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp @@ -204,9 +204,7 @@ const char* RequeueNodeCmd::desc() { } void RequeueNodeCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(RequeueNodeCmd::arg(), - boost::program_options::value>()->multitoken(), - RequeueNodeCmd::desc()); + desc.add_options()(RequeueNodeCmd::arg(), boost::program_options::value>()->multitoken()); } void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { auto args = vm[RequeueNodeCmd::arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp index 14fbf52e0..29bb97e08 100644 --- a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp @@ -153,8 +153,7 @@ const char* RunNodeCmd::desc() { } void RunNodeCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - RunNodeCmd::arg(), boost::program_options::value>()->multitoken(), RunNodeCmd::desc()); + desc.add_options()(RunNodeCmd::arg(), boost::program_options::value>()->multitoken()); } void RunNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ace) const { auto args = vm[RunNodeCmd::arg()].as>(); diff --git a/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp b/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp index fa382ad4d..dc07da7dd 100644 --- a/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp @@ -61,7 +61,7 @@ static const char* arg_desc() { } void ServerVersionCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()(CtsApi::server_version_arg(), arg_desc()); + desc.add_options()(CtsApi::server_version_arg(), ""); } void ServerVersionCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ace) const { diff --git a/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp b/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp index 9afe6f90c..731dd43e4 100644 --- a/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp @@ -86,8 +86,7 @@ const char* ShowCmd::desc() { } void ShowCmd::addOption(boost::program_options::options_description& desc) const { - desc.add_options()( - ShowCmd::arg(), boost::program_options::value()->implicit_value(std::string{}), ShowCmd::desc()); + desc.add_options()(ShowCmd::arg(), boost::program_options::value()->implicit_value(std::string{})); } void ShowCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* ac) const { std::string show_state = vm[ShowCmd::arg()].as(); diff --git a/libs/base/src/ecflow/base/cts/user/ZombieCmd.cpp b/libs/base/src/ecflow/base/cts/user/ZombieCmd.cpp index 9704e6e8c..e780d655a 100644 --- a/libs/base/src/ecflow/base/cts/user/ZombieCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ZombieCmd.cpp @@ -212,78 +212,33 @@ void ZombieCmd::addOption(boost::program_options::options_description& desc) con switch (user_action_) { case ZombieCtrlAction::FOB: { - desc.add_options()( - CtsApi::zombieFobArg(), - boost::program_options::value>()->multitoken(), - "Locates the task in the servers list of zombies, and sets to fob.\n" - "This default behaviour of the child commands(label,event,meter) is to fob\n" - "Next time the child commands (init,event,meter,label,abort,complete,wait,queue) communicate\n" - "with the server, they will complete successfully (but without updating the node tree)\n" - "allowing the job to finish.\n" - "The references to the zombie in the server is automatically deleted after 1 hour\n" - " args = list of task paths, at least one expected\n" - " --zombie_fob=/path/to/task1 /path/to/task2"); + desc.add_options()(CtsApi::zombieFobArg(), + boost::program_options::value>()->multitoken()); break; } case ZombieCtrlAction::FAIL: { desc.add_options()(CtsApi::zombieFailArg(), - boost::program_options::value>()->multitoken(), - "Locates the task in the servers list of zombies, and sets to fail.\n" - "Next time a child command (init,event,meter,label,abort,complete) which " - "matches zombie, communicates with the server, will be set to fail.\n" - "Depending on the job setup this may force a abort, the abort will also fail.\n" - "Hence job structure should use 'set -e' in the error trapping functions to prevent\n" - "infinite recursion.\n" - "The references to the zombie in the server is automatically deleted after 1 hour\n" - " args = list of task paths, at least one expected\n" - " --zombie_fail=/path/to/task /path/to/task2"); + boost::program_options::value>()->multitoken()); break; } case ZombieCtrlAction::ADOPT: { desc.add_options()(CtsApi::zombieAdoptArg(), - boost::program_options::value>()->multitoken(), - "Locates the task in the servers list of zombies, and sets to adopt.\n" - "Next time a child command (init,event,meter,label,abort,complete,wait queue) " - "communicates with the server, the password on the zombie is adopted by the task.\n" - "This is only allowed if the process id matches, otherwise an error is issued.\n" - "The zombie reference stored in the server is then deleted.\n" - " args = list of task paths, at least one expected\n" - " --zombie_adopt=/path/to/task /path/to/task2"); + boost::program_options::value>()->multitoken()); break; } case ZombieCtrlAction::REMOVE: { - desc.add_options()( - CtsApi::zombieRemoveArg(), - boost::program_options::value>()->multitoken(), - "Locates the task in the servers list of zombies, and removes it.\n" - "Since a job typically has many child commands (i.e init, complete, event, meter, label, wait, queue)\n" - "the zombie may reappear\n" - " args = list of task paths, at least one expected\n" - " --zombie_remove=/path/to/task /path/to/task2"); + desc.add_options()(CtsApi::zombieRemoveArg(), + boost::program_options::value>()->multitoken()); break; } case ZombieCtrlAction::BLOCK: { desc.add_options()(CtsApi::zombieBlockArg(), - boost::program_options::value>()->multitoken(), - "Locates the task in the servers list of zombies, and sets flags to block it.\n" - "This is default behaviour of the child commands(init,abort,complete,wait,queue)\n" - "when the server cannot match the passwords. Each child commands will continue\n" - "attempting to connect to the server for 24 hours, and will then return an error.\n" - "The connection timeout can be configured with environment ECF_TIMEOUT\n" - " args = list of task paths, at least one expected\n" - " --zombie_block=/path/to/task /path/to/task2"); + boost::program_options::value>()->multitoken()); break; } case ZombieCtrlAction::KILL: { desc.add_options()(CtsApi::zombieKillArg(), - boost::program_options::value>()->multitoken(), - "Locates the task in the servers list of zombies, and sets flags to kill\n" - "The kill is done using ECF_KILL_CMD, but using the process_id from the zombie\n" - "The job is allowed to continue until the kill is received\n" - "Can only kill zombies that have an associated Task, hence path zombies\n" - "must be killed manually.\n" - " arg = list of task paths, at least one expected\n" - " --zombie_kill=/path/to/task /path/to/task2"); + boost::program_options::value>()->multitoken()); break; } default: diff --git a/libs/client/src/ecflow/client/ClientOptions.cpp b/libs/client/src/ecflow/client/ClientOptions.cpp index 1754c4b03..339e1c273 100644 --- a/libs/client/src/ecflow/client/ClientOptions.cpp +++ b/libs/client/src/ecflow/client/ClientOptions.cpp @@ -53,38 +53,16 @@ ClientOptions::ClientOptions() { // Allow the host,port and rid to be overridden by the command line // This allows the jobs, which make other calls to ecflow_client from interfering with each other // clang-format off - desc_->add_options()( - "rid", - po::value()->implicit_value(std::string{}), - "When specified overrides the environment variable ECF_RID. Can only be used for child commands."); - desc_->add_options()( - "port", - po::value()->implicit_value(std::string{}), - "When specified overrides the environment variable ECF_PORT and default port: '3141'"); - desc_->add_options()( - "host", - po::value()->implicit_value(std::string{}), - "When specified overrides the environment variable ECF_HOST and default host: 'localhost'"); - desc_->add_options()( - "user", - po::value()->implicit_value(std::string{}), - "Specifies the user name used to contact the server. Must be used in combination with option --password."); - desc_->add_options()( - "password", - po::value()->implicit_value(std::string{}), - "Specifies the password used to contact the server. Must be used in combination with option --user."); + desc_->add_options()("rid", po::value()->implicit_value(std::string{})); + desc_->add_options()("port", po::value()->implicit_value(std::string{})); + desc_->add_options()("host", po::value()->implicit_value(std::string{})); + desc_->add_options()("user", po::value()->implicit_value(std::string{})); + desc_->add_options()("password", po::value()->implicit_value(std::string{})); #ifdef ECF_OPENSSL - desc_->add_options()( - "ssl", - "Enables the use of SSL when contacting the server.\n" - "When specified overrides the environment variable ECF_SSL."); + desc_->add_options()("ssl", ""); #endif - desc_->add_options()( - "http", - "Enables communication over HTTP between client/server.\n"); - desc_->add_options()( - "https", - "Enables communication over HTTPS between client/server.\n"); + desc_->add_options()("http", ""); + desc_->add_options()("https", ""); // clang-format on } From 2042e89de9572813f5283b5f2884a3c5fa7eda1f Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 19:27:13 +0100 Subject: [PATCH 35/49] Stop falling back to Cmd::desc() in thrown parser errors The ~29 call sites migrated to route thrown-error text through HelpCatalog::description_for() kept a fallback to the original Cmd::desc()/arg_desc() text for the (theoretical) case where the manifest lacked an entry. That fallback duplicates the same "unreachable in practice" reasoning already applied to Help.cpp's own Boost-description fallback, which was replaced with a fixed warning message rather than a second copy of the text. Replace every .value_or(Cmd::desc()) with .value_or("Description not provided for this option"), for consistency with that same decision. --- .../src/ecflow/base/cts/user/AlterCmd.cpp | 20 ++++++++------ .../src/ecflow/base/cts/user/BeginCmd.cpp | 8 +++--- .../src/ecflow/base/cts/user/CFileCmd.cpp | 7 ++--- .../src/ecflow/base/cts/user/CheckPtCmd.cpp | 27 ++++++++++--------- .../ecflow/base/cts/user/EditScriptCmd.cpp | 25 ++++++++--------- .../src/ecflow/base/cts/user/ForceCmd.cpp | 26 +++++++++--------- .../src/ecflow/base/cts/user/FreeDepCmd.cpp | 23 ++++++++-------- .../src/ecflow/base/cts/user/LoadDefsCmd.cpp | 2 +- libs/base/src/ecflow/base/cts/user/LogCmd.cpp | 5 ++-- .../base/src/ecflow/base/cts/user/PlugCmd.cpp | 7 ++--- .../src/ecflow/base/cts/user/QueryCmd.cpp | 12 +++++---- .../ecflow/base/cts/user/RequeueNodeCmd.cpp | 15 ++++++----- .../src/ecflow/base/cts/user/RunNodeCmd.cpp | 18 ++++++------- 13 files changed, 106 insertions(+), 89 deletions(-) diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp index bc4739c12..e784e89ff 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -811,7 +811,8 @@ AlterCmd::Add_attr_type AlterCmd::get_add_attr_type(const std::string& attr_type } ss << valid[i]; } - ss << "] but found " << attr_type << "\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); + ss << "] but found " << attr_type << "\n" + << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1064,7 +1065,8 @@ AlterCmd::Delete_attr_type AlterCmd::get_delete_attr_type(const std::string& att } ss << valid[i]; } - ss << "] but found " << attr_type << "\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); + ss << "] but found " << attr_type << "\n" + << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1295,7 +1297,7 @@ AlterCmd::Change_attr_type AlterCmd::get_change_attr_type(const std::string& att } ss << valid[i]; } - ss << "]\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); + ss << "]\n" << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1761,7 +1763,7 @@ ecf::Flag::Type AlterCmd::get_flag_type(const std::string& flag_type) const { } ss << valid[i]; } - ss << "]\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); + ss << "]\n" << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); throw std::runtime_error(ss.str()); } return theFlagType; @@ -1791,7 +1793,8 @@ void AlterCmd::check_sort_attr_type(const std::string& attr_type) const { } ss << valid[i]; } - ss << "] but found " << attr_type << "\n" << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()); + ss << "] but found " << attr_type << "\n" + << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); throw std::runtime_error(ss.str()); } } @@ -1814,9 +1817,10 @@ void AlterCmd::create_sort_attributes(Cmd_ptr& cmd, std::string value; if (options.size() == 3) { if (options[2] != "recursive") { - throw std::runtime_error(MESSAGE("AlterCmd: sort: Expected third argument to be 'recursive' but found '" - << options[2] << "\n" - << HelpCatalog::description_for("alter").value_or(AlterCmd::desc()))); + throw std::runtime_error( + MESSAGE("AlterCmd: sort: Expected third argument to be 'recursive' but found '" + << options[2] << "\n" + << HelpCatalog::description_for("alter").value_or("Description not provided for this option"))); } value = "recursive"; } diff --git a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp index 127e0173c..c48ffa100 100644 --- a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp @@ -182,10 +182,10 @@ void BeginCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A force = true; } else { - throw std::runtime_error(MESSAGE("BeginCmd: Expect zero, one or 2 arguments, but found " - << lineTokens.size() << " arguments\n" - << HelpCatalog::description_for("begin").value_or(BeginCmd::desc()) - << "\n")); + throw std::runtime_error(MESSAGE( + "BeginCmd: Expect zero, one or 2 arguments, but found " + << lineTokens.size() << " arguments\n" + << HelpCatalog::description_for("begin").value_or("Description not provided for this option") << "\n")); } } diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp index 6da60a97d..1653ea46f 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp @@ -356,9 +356,10 @@ void CFileCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A } if (args.size() < 1) { - throw std::runtime_error(MESSAGE("CFileCmd: At least one arguments expected for File. Found " - << args.size() << "\n" - << HelpCatalog::description_for("file").value_or(CFileCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "CFileCmd: At least one arguments expected for File. Found " + << args.size() << "\n" + << HelpCatalog::description_for("file").value_or("Description not provided for this option") << "\n")); } std::string pathToNode = args[0]; diff --git a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp index 694111074..f9354269a 100644 --- a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp @@ -141,15 +141,16 @@ static int parse_check_pt_interval(const std::string& the_arg) { check_pt_interval = ecf::convert_to(the_arg); } catch (...) { - throw std::runtime_error(MESSAGE("check_pt: Illegal argument(" - << the_arg - << "), expected [ never | on_time | on_time: | always | ]\n" - << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); + throw std::runtime_error( + MESSAGE("check_pt: Illegal argument(" + << the_arg << "), expected [ never | on_time | on_time: | always | ]\n" + << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); } if (check_pt_interval <= 0) { - throw std::runtime_error(MESSAGE("check_pt: interval(" - << check_pt_interval << ") must be greater than zero :\n" - << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); + throw std::runtime_error( + MESSAGE("check_pt: interval(" + << check_pt_interval << ") must be greater than zero :\n" + << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); } return check_pt_interval; } @@ -165,12 +166,13 @@ static int parse_check_pt_alarm_time(const std::string& the_arg, int colon_pos) throw std::runtime_error(MESSAGE( "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | alarm::integer> | always | ]\n" - << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); + << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); } if (check_pt_alarm_time <= 0) { - throw std::runtime_error(MESSAGE("check_pt: alarm time(" - << check_pt_alarm_time << ") must be greater than zero :\n" - << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); + throw std::runtime_error( + MESSAGE("check_pt: alarm time(" + << check_pt_alarm_time << ") must be greater than zero :\n" + << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); } return check_pt_alarm_time; } @@ -215,7 +217,8 @@ void CheckPtCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | alarm: | always | ]\n" - << HelpCatalog::description_for("check_pt").value_or(arg_desc()))); + << HelpCatalog::description_for("check_pt") + .value_or("Description not provided for this option"))); } check_pt_interval = parse_check_pt_interval(interval); } diff --git a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp index f738f7709..674970bed 100644 --- a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp @@ -352,9 +352,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } if (args.size() < 2) { - throw std::runtime_error( - MESSAGE("EditScriptCmd:At least 2 arguments required:\n" - << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); + throw std::runtime_error(MESSAGE( + "EditScriptCmd:At least 2 arguments required:\n" + << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); } std::string path_to_task = args[0]; @@ -398,7 +398,7 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } ss << edit_types[i]; } - ss << "]\n" << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()); + ss << "]\n" << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"); throw std::runtime_error(ss.str()); } @@ -408,9 +408,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& return; } else { - throw std::runtime_error( - MESSAGE("When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" - << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); + throw std::runtime_error(MESSAGE( + "When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" + << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); } } @@ -425,9 +425,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } } if ((create_alias || !run_alias) && edit_type != EditScriptCmd::SUBMIT_USER_FILE) { - throw std::runtime_error( - MESSAGE("The create_alias option is only valid when the second argument is 'submit_file' \n" - << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); + throw std::runtime_error(MESSAGE( + "The create_alias option is only valid when the second argument is 'submit_file' \n" + << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); } if (args.size() >= 3 && args.size() <= 5) { @@ -469,8 +469,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } } - throw std::runtime_error(MESSAGE("Wrong number of arguments specified\n" - << HelpCatalog::description_for("edit_script").value_or(EditScriptCmd::desc()))); + throw std::runtime_error( + MESSAGE("Wrong number of arguments specified\n" + << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); } std::ostream& operator<<(std::ostream& os, const EditScriptCmd& c) { diff --git a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp index 1c0271f22..06a9f0313 100644 --- a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp @@ -252,23 +252,25 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A } if (args.size() < 2) { - throw std::runtime_error(MESSAGE("ForceCmd: At least two arguments expected for Force. Found " - << args.size() << "\n" - << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "ForceCmd: At least two arguments expected for Force. Found " + << args.size() << "\n" + << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); } std::vector options, paths; split_args_to_options_and_paths( args, options, paths, true /*treat_colon_in_path_as_path*/); // relative order is still preserved if (paths.empty()) { - throw std::runtime_error(MESSAGE("ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" - << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" + << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); } if (options.empty()) { - throw std::runtime_error( - MESSAGE("ForceCmd: Invalid argument list. Expected of:\n" - << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" - << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "ForceCmd: Invalid argument list. Expected of:\n" + << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" + << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); } bool is_valid_state = false; @@ -293,9 +295,9 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A stateOrEvent = options[i]; } else { - throw std::runtime_error(MESSAGE("ForceCmd: Invalid argument \n" - << HelpCatalog::description_for("force").value_or(ForceCmd::desc()) - << "\n")); + throw std::runtime_error(MESSAGE( + "ForceCmd: Invalid argument \n" + << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); } } diff --git a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp index cd6ccdb9d..9372d8c26 100644 --- a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp @@ -146,18 +146,18 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, } if (args.size() < 1) { - throw std::runtime_error(MESSAGE("FreeDepCmd: At least one arguments expected for Free dependencies. Found " - << args.size() << "\n" - << HelpCatalog::description_for("free-dep").value_or(FreeDepCmd::desc()) - << "\n")); + throw std::runtime_error(MESSAGE( + "FreeDepCmd: At least one arguments expected for Free dependencies. Found " + << args.size() << "\n" + << HelpCatalog::description_for("free-dep").value_or("Description not provided for this option") << "\n")); } std::vector options, paths; split_args_to_options_and_paths(args, options, paths); // relative order is still preserved if (paths.empty()) { - throw std::runtime_error( - MESSAGE("FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" - << HelpCatalog::description_for("free-dep").value_or(FreeDepCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" + << HelpCatalog::description_for("free-dep").value_or("Description not provided for this option") << "\n")); } bool trigger = options.empty(); // If no options default to freeing trigger dependencies @@ -179,10 +179,11 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, time = true; } else { - throw std::runtime_error(MESSAGE("FreeDepCmd: Invalid argument(" - << options[i] << ")\n" - << HelpCatalog::description_for("free-dep").value_or(FreeDepCmd::desc()) - << "\n")); + throw std::runtime_error( + MESSAGE("FreeDepCmd: Invalid argument(" + << options[i] << ")\n" + << HelpCatalog::description_for("free-dep").value_or("Description not provided for this option") + << "\n")); } } assert(trigger || all || date || time); // at least one must be true diff --git a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp index 817d9dc1d..a9ff342ce 100644 --- a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp @@ -46,7 +46,7 @@ LoadDefsCmd::LoadDefsCmd(const std::string& defs_filename, if (defs_filename_.empty()) { throw std::runtime_error( MESSAGE("LoadDefsCmd::LoadDefsCmd: The pathname to the definition file must be provided\n" - << HelpCatalog::description_for("load").value_or(LoadDefsCmd::desc()))); + << HelpCatalog::description_for("load").value_or("Description not provided for this option"))); } defs_ptr defs = Defs::create(); diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp index 3469ab84a..bcfcd45f5 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp @@ -299,8 +299,9 @@ void LogCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, Abs return; } - throw std::runtime_error(MESSAGE("LogCmd: The arguments have not been specified correctly\n" - << HelpCatalog::description_for("log").value_or(LogCmd::desc()))); + throw std::runtime_error( + MESSAGE("LogCmd: The arguments have not been specified correctly\n" + << HelpCatalog::description_for("log").value_or("Description not provided for this option"))); } std::ostream& operator<<(std::ostream& os, const LogCmd& c) { diff --git a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp index 8bda811ae..9f4d49b2e 100644 --- a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp @@ -304,9 +304,10 @@ void PlugCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, Ab } if (args.size() != 2) { - throw std::runtime_error(MESSAGE("PlugCmd: Two arguments are expected, found " - << args.size() << "\n" - << HelpCatalog::description_for("plug").value_or(PlugCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "PlugCmd: Two arguments are expected, found " + << args.size() << "\n" + << HelpCatalog::description_for("plug").value_or("Description not provided for this option") << "\n")); } std::string sourceNode = args[0]; diff --git a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp index 844848c0e..068d6d0b9 100644 --- a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp @@ -109,9 +109,10 @@ void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A << query_type << " args size = " << args.size() << " expected 2 arguments")); } if (attribute.empty()) { - throw std::runtime_error(MESSAGE("QueryCmd: no attribute specified: query type: " - << query_type << " path+attribute: " << path_and_name << "\n" - << HelpCatalog::description_for("query").value_or(QueryCmd::desc()))); + throw std::runtime_error( + MESSAGE("QueryCmd: no attribute specified: query type: " + << query_type << " path+attribute: " << path_and_name << "\n" + << HelpCatalog::description_for("query").value_or("Description not provided for this option"))); } } else if (query_type == "trigger") { @@ -125,8 +126,9 @@ void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A } } if (attribute.empty()) { - throw std::runtime_error(MESSAGE("QueryCmd: no attribute specified: query type: trigger\n" - << HelpCatalog::description_for("query").value_or(QueryCmd::desc()))); + throw std::runtime_error( + MESSAGE("QueryCmd: no attribute specified: query type: trigger\n" + << HelpCatalog::description_for("query").value_or("Description not provided for this option"))); } } else if (query_type == "state" || query_type == "dstate") { diff --git a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp index 4fdadf43d..12f0d6b9e 100644 --- a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp @@ -227,7 +227,7 @@ void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& throw std::runtime_error(MESSAGE( "RequeueNodeCmd: No paths specified. At least one path expected. Paths must begin with a leading '/' " "character\n" - << HelpCatalog::description_for("requeue").value_or(RequeueNodeCmd::desc()) << "\n")); + << HelpCatalog::description_for("requeue").value_or("Description not provided for this option") << "\n")); } RequeueNodeCmd::Option option = RequeueNodeCmd::NO_OPTION; @@ -246,15 +246,16 @@ void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } } else { - throw std::runtime_error(MESSAGE("RequeueNodeCmd: RequeueNodeCmd: Expected : [force | abort ] paths.\n" - << HelpCatalog::description_for("requeue").value_or(RequeueNodeCmd::desc()) - << "\n")); + throw std::runtime_error( + MESSAGE("RequeueNodeCmd: RequeueNodeCmd: Expected : [force | abort ] paths.\n" + << HelpCatalog::description_for("requeue").value_or("Description not provided for this option") + << "\n")); } } if (options.size() > 1) { - throw std::runtime_error(MESSAGE("RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" - << HelpCatalog::description_for("requeue").value_or(RequeueNodeCmd::desc()) - << "\n")); + throw std::runtime_error(MESSAGE( + "RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" + << HelpCatalog::description_for("requeue").value_or("Description not provided for this option") << "\n")); } cmd = std::make_shared(paths, option); diff --git a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp index 29bb97e08..ae8c48af3 100644 --- a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp @@ -165,25 +165,25 @@ void RunNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, std::vector options, paths; split_args_to_options_and_paths(args, options, paths); // relative order is still preserved if (paths.empty()) { - throw std::runtime_error( - MESSAGE("RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" - << HelpCatalog::description_for("run").value_or(RunNodeCmd::desc()) << "\n")); + throw std::runtime_error(MESSAGE( + "RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" + << HelpCatalog::description_for("run").value_or("Description not provided for this option") << "\n")); } bool force = false; if (!options.empty()) { if (options.size() != 1) { - throw std::runtime_error(MESSAGE("RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" - << HelpCatalog::description_for("run").value_or(RunNodeCmd::desc()) - << "\n")); + throw std::runtime_error(MESSAGE( + "RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" + << HelpCatalog::description_for("run").value_or("Description not provided for this option") << "\n")); } if (options[0].find("force") != std::string::npos) { force = true; } else { - throw std::runtime_error(MESSAGE("RunNodeCmd: Expected force \n" - << HelpCatalog::description_for("run").value_or(RunNodeCmd::desc()) - << "\n")); + throw std::runtime_error(MESSAGE( + "RunNodeCmd: Expected force \n" + << HelpCatalog::description_for("run").value_or("Description not provided for this option") << "\n")); } } cmd = std::make_shared(paths, force); From 6813360384b6562d3f1c1ab89993716ac7afd39a Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 19:31:22 +0100 Subject: [PATCH 36/49] Add HelpCatalog::not_provided, replacing the literal string The "Description not provided for this option" message used to be a separate string literal duplicated at every fallback call site: in Help.cpp's two rendering paths, CommandDesignerWidget's two lookups, and the ~29 thrown-parser-error sites across 13 command classes. Add a single ecf::HelpCatalog::not_provided constant and reference it everywhere instead, so the message exists in exactly one place. --- Viewer/ecflowUI/src/CommandDesignerWidget.cpp | 7 ++--- libs/base/src/ecflow/base/HelpCatalog.cpp | 2 ++ libs/base/src/ecflow/base/HelpCatalog.hpp | 10 +++++++ .../src/ecflow/base/cts/user/AlterCmd.cpp | 12 ++++---- .../src/ecflow/base/cts/user/BeginCmd.cpp | 8 +++--- .../src/ecflow/base/cts/user/CFileCmd.cpp | 8 +++--- .../src/ecflow/base/cts/user/CheckPtCmd.cpp | 21 ++++++-------- .../ecflow/base/cts/user/EditScriptCmd.cpp | 22 +++++++-------- .../src/ecflow/base/cts/user/ForceCmd.cpp | 28 +++++++++---------- .../src/ecflow/base/cts/user/FreeDepCmd.cpp | 17 ++++++----- .../src/ecflow/base/cts/user/LoadDefsCmd.cpp | 2 +- libs/base/src/ecflow/base/cts/user/LogCmd.cpp | 5 ++-- .../base/src/ecflow/base/cts/user/PlugCmd.cpp | 8 +++--- .../src/ecflow/base/cts/user/QueryCmd.cpp | 4 +-- .../ecflow/base/cts/user/RequeueNodeCmd.cpp | 11 ++++---- .../src/ecflow/base/cts/user/RunNodeCmd.cpp | 18 ++++++------ libs/client/src/ecflow/client/Help.cpp | 4 +-- 17 files changed, 96 insertions(+), 91 deletions(-) diff --git a/Viewer/ecflowUI/src/CommandDesignerWidget.cpp b/Viewer/ecflowUI/src/CommandDesignerWidget.cpp index 04ded3a7d..10ff4f522 100644 --- a/Viewer/ecflowUI/src/CommandDesignerWidget.cpp +++ b/Viewer/ecflowUI/src/CommandDesignerWidget.cpp @@ -229,14 +229,13 @@ void CommandDesignerWidget::showCommandHelp(QListWidgetItem* item, bool showFull ); if (od) { - std::string summary = - ecf::HelpCatalog::summary_for(od->long_name()).value_or("Description not provided for this option"); - QString text = qCommand + QString(": "); + std::string summary = ecf::HelpCatalog::summary_for(od->long_name()).value_or(ecf::HelpCatalog::not_provided); + QString text = qCommand + QString(": "); commandHelpLabel_->setText(text + QString::fromStdString(summary)); if (showFullHelp) { std::string description = - ecf::HelpCatalog::description_for(od->long_name()).value_or("Description not provided for this option"); + ecf::HelpCatalog::description_for(od->long_name()).value_or(ecf::HelpCatalog::not_provided); commandManPage_->setText(qCommand + "\n\n" + QString::fromStdString(description)); } } diff --git a/libs/base/src/ecflow/base/HelpCatalog.cpp b/libs/base/src/ecflow/base/HelpCatalog.cpp index b6f72793d..2330d7b98 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.cpp +++ b/libs/base/src/ecflow/base/HelpCatalog.cpp @@ -14,6 +14,8 @@ namespace ecf { +const std::string HelpCatalog::not_provided = "Description not provided for this option"; + const nlohmann::json& HelpCatalog::manifest() { static const nlohmann::json instance = nlohmann::json::parse(client_help_json); return instance; diff --git a/libs/base/src/ecflow/base/HelpCatalog.hpp b/libs/base/src/ecflow/base/HelpCatalog.hpp index 1d7a2f162..9687567f3 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.hpp +++ b/libs/base/src/ecflow/base/HelpCatalog.hpp @@ -97,6 +97,16 @@ class HelpCatalog { /// static std::optional description_for(const std::string& name); + /// + /// @brief Placeholder text for a command or option with no manifest entry. + /// + /// Rendered in place of a description whenever @ref summary_for or + /// @ref description_for returns std::nullopt, instead of falling back to a + /// second, independent copy of the text (e.g. a C++ literal that could drift + /// from the manifest). + /// + static const std::string not_provided; + private: static const nlohmann::json* find_by_name(const nlohmann::json& array, const std::string& name); static const nlohmann::json* entry_for(const std::string& name); diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp index e784e89ff..65b4037a0 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -812,7 +812,7 @@ AlterCmd::Add_attr_type AlterCmd::get_add_attr_type(const std::string& attr_type ss << valid[i]; } ss << "] but found " << attr_type << "\n" - << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); + << HelpCatalog::description_for("alter").value_or(HelpCatalog::not_provided); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1066,7 +1066,7 @@ AlterCmd::Delete_attr_type AlterCmd::get_delete_attr_type(const std::string& att ss << valid[i]; } ss << "] but found " << attr_type << "\n" - << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); + << HelpCatalog::description_for("alter").value_or(HelpCatalog::not_provided); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1297,7 +1297,7 @@ AlterCmd::Change_attr_type AlterCmd::get_change_attr_type(const std::string& att } ss << valid[i]; } - ss << "]\n" << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); + ss << "]\n" << HelpCatalog::description_for("alter").value_or(HelpCatalog::not_provided); throw std::runtime_error(ss.str()); } return theAttrType; @@ -1763,7 +1763,7 @@ ecf::Flag::Type AlterCmd::get_flag_type(const std::string& flag_type) const { } ss << valid[i]; } - ss << "]\n" << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); + ss << "]\n" << HelpCatalog::description_for("alter").value_or(HelpCatalog::not_provided); throw std::runtime_error(ss.str()); } return theFlagType; @@ -1794,7 +1794,7 @@ void AlterCmd::check_sort_attr_type(const std::string& attr_type) const { ss << valid[i]; } ss << "] but found " << attr_type << "\n" - << HelpCatalog::description_for("alter").value_or("Description not provided for this option"); + << HelpCatalog::description_for("alter").value_or(HelpCatalog::not_provided); throw std::runtime_error(ss.str()); } } @@ -1820,7 +1820,7 @@ void AlterCmd::create_sort_attributes(Cmd_ptr& cmd, throw std::runtime_error( MESSAGE("AlterCmd: sort: Expected third argument to be 'recursive' but found '" << options[2] << "\n" - << HelpCatalog::description_for("alter").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("alter").value_or(HelpCatalog::not_provided))); } value = "recursive"; } diff --git a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp index c48ffa100..9ad749fe0 100644 --- a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp @@ -182,10 +182,10 @@ void BeginCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A force = true; } else { - throw std::runtime_error(MESSAGE( - "BeginCmd: Expect zero, one or 2 arguments, but found " - << lineTokens.size() << " arguments\n" - << HelpCatalog::description_for("begin").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error( + MESSAGE("BeginCmd: Expect zero, one or 2 arguments, but found " + << lineTokens.size() << " arguments\n" + << HelpCatalog::description_for("begin").value_or(HelpCatalog::not_provided) << "\n")); } } diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp index 1653ea46f..3d223655a 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp @@ -356,10 +356,10 @@ void CFileCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A } if (args.size() < 1) { - throw std::runtime_error(MESSAGE( - "CFileCmd: At least one arguments expected for File. Found " - << args.size() << "\n" - << HelpCatalog::description_for("file").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("CFileCmd: At least one arguments expected for File. Found " + << args.size() << "\n" + << HelpCatalog::description_for("file").value_or(HelpCatalog::not_provided) + << "\n")); } std::string pathToNode = args[0]; diff --git a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp index f9354269a..0bda3e6c2 100644 --- a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp @@ -144,13 +144,12 @@ static int parse_check_pt_interval(const std::string& the_arg) { throw std::runtime_error( MESSAGE("check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | always | ]\n" - << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("check_pt").value_or(HelpCatalog::not_provided))); } if (check_pt_interval <= 0) { - throw std::runtime_error( - MESSAGE("check_pt: interval(" - << check_pt_interval << ") must be greater than zero :\n" - << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); + throw std::runtime_error(MESSAGE( + "check_pt: interval(" << check_pt_interval << ") must be greater than zero :\n" + << HelpCatalog::description_for("check_pt").value_or(HelpCatalog::not_provided))); } return check_pt_interval; } @@ -166,13 +165,12 @@ static int parse_check_pt_alarm_time(const std::string& the_arg, int colon_pos) throw std::runtime_error(MESSAGE( "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | alarm::integer> | always | ]\n" - << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("check_pt").value_or(HelpCatalog::not_provided))); } if (check_pt_alarm_time <= 0) { - throw std::runtime_error( - MESSAGE("check_pt: alarm time(" - << check_pt_alarm_time << ") must be greater than zero :\n" - << HelpCatalog::description_for("check_pt").value_or("Description not provided for this option"))); + throw std::runtime_error(MESSAGE( + "check_pt: alarm time(" << check_pt_alarm_time << ") must be greater than zero :\n" + << HelpCatalog::description_for("check_pt").value_or(HelpCatalog::not_provided))); } return check_pt_alarm_time; } @@ -217,8 +215,7 @@ void CheckPtCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, "check_pt: Illegal argument(" << the_arg << "), expected [ never | on_time | on_time: | alarm: | always | ]\n" - << HelpCatalog::description_for("check_pt") - .value_or("Description not provided for this option"))); + << HelpCatalog::description_for("check_pt").value_or(HelpCatalog::not_provided))); } check_pt_interval = parse_check_pt_interval(interval); } diff --git a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp index 674970bed..52673e5c4 100644 --- a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp @@ -352,9 +352,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } if (args.size() < 2) { - throw std::runtime_error(MESSAGE( - "EditScriptCmd:At least 2 arguments required:\n" - << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); + throw std::runtime_error( + MESSAGE("EditScriptCmd:At least 2 arguments required:\n" + << HelpCatalog::description_for("edit_script").value_or(HelpCatalog::not_provided))); } std::string path_to_task = args[0]; @@ -398,7 +398,7 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } ss << edit_types[i]; } - ss << "]\n" << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"); + ss << "]\n" << HelpCatalog::description_for("edit_script").value_or(HelpCatalog::not_provided); throw std::runtime_error(ss.str()); } @@ -408,9 +408,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& return; } else { - throw std::runtime_error(MESSAGE( - "When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" - << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); + throw std::runtime_error( + MESSAGE("When two arguments specified, the second argument must be one of [ edit | pre_process ]\n" + << HelpCatalog::description_for("edit_script").value_or(HelpCatalog::not_provided))); } } @@ -425,9 +425,9 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& } } if ((create_alias || !run_alias) && edit_type != EditScriptCmd::SUBMIT_USER_FILE) { - throw std::runtime_error(MESSAGE( - "The create_alias option is only valid when the second argument is 'submit_file' \n" - << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); + throw std::runtime_error( + MESSAGE("The create_alias option is only valid when the second argument is 'submit_file' \n" + << HelpCatalog::description_for("edit_script").value_or(HelpCatalog::not_provided))); } if (args.size() >= 3 && args.size() <= 5) { @@ -471,7 +471,7 @@ void EditScriptCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& throw std::runtime_error( MESSAGE("Wrong number of arguments specified\n" - << HelpCatalog::description_for("edit_script").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("edit_script").value_or(HelpCatalog::not_provided))); } std::ostream& operator<<(std::ostream& os, const EditScriptCmd& c) { diff --git a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp index 06a9f0313..e51bf0de0 100644 --- a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp @@ -252,25 +252,25 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A } if (args.size() < 2) { - throw std::runtime_error(MESSAGE( - "ForceCmd: At least two arguments expected for Force. Found " - << args.size() << "\n" - << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("ForceCmd: At least two arguments expected for Force. Found " + << args.size() << "\n" + << HelpCatalog::description_for("force").value_or(HelpCatalog::not_provided) + << "\n")); } std::vector options, paths; split_args_to_options_and_paths( args, options, paths, true /*treat_colon_in_path_as_path*/); // relative order is still preserved if (paths.empty()) { - throw std::runtime_error(MESSAGE( - "ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" - << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("ForceCmd: No paths specified. Paths must begin with a leading '/' character\n" + << HelpCatalog::description_for("force").value_or(HelpCatalog::not_provided) + << "\n")); } if (options.empty()) { - throw std::runtime_error(MESSAGE( - "ForceCmd: Invalid argument list. Expected of:\n" - << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" - << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error( + MESSAGE("ForceCmd: Invalid argument list. Expected of:\n" + << "[ unknown | complete | queued | submitted | active | aborted | clear | set]\n" + << HelpCatalog::description_for("force").value_or(HelpCatalog::not_provided) << "\n")); } bool is_valid_state = false; @@ -295,9 +295,9 @@ void ForceCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A stateOrEvent = options[i]; } else { - throw std::runtime_error(MESSAGE( - "ForceCmd: Invalid argument \n" - << HelpCatalog::description_for("force").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error( + MESSAGE("ForceCmd: Invalid argument \n" + << HelpCatalog::description_for("force").value_or(HelpCatalog::not_provided) << "\n")); } } diff --git a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp index 9372d8c26..42fa6fc82 100644 --- a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp @@ -146,18 +146,18 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, } if (args.size() < 1) { - throw std::runtime_error(MESSAGE( - "FreeDepCmd: At least one arguments expected for Free dependencies. Found " - << args.size() << "\n" - << HelpCatalog::description_for("free-dep").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("FreeDepCmd: At least one arguments expected for Free dependencies. Found " + << args.size() << "\n" + << HelpCatalog::description_for("free-dep").value_or(HelpCatalog::not_provided) + << "\n")); } std::vector options, paths; split_args_to_options_and_paths(args, options, paths); // relative order is still preserved if (paths.empty()) { - throw std::runtime_error(MESSAGE( - "FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" - << HelpCatalog::description_for("free-dep").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error( + MESSAGE("FreeDepCmd: No paths specified. Paths must begin with a leading '/' character\n" + << HelpCatalog::description_for("free-dep").value_or(HelpCatalog::not_provided) << "\n")); } bool trigger = options.empty(); // If no options default to freeing trigger dependencies @@ -182,8 +182,7 @@ void FreeDepCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, throw std::runtime_error( MESSAGE("FreeDepCmd: Invalid argument(" << options[i] << ")\n" - << HelpCatalog::description_for("free-dep").value_or("Description not provided for this option") - << "\n")); + << HelpCatalog::description_for("free-dep").value_or(HelpCatalog::not_provided) << "\n")); } } assert(trigger || all || date || time); // at least one must be true diff --git a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp index a9ff342ce..a4f156333 100644 --- a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp @@ -46,7 +46,7 @@ LoadDefsCmd::LoadDefsCmd(const std::string& defs_filename, if (defs_filename_.empty()) { throw std::runtime_error( MESSAGE("LoadDefsCmd::LoadDefsCmd: The pathname to the definition file must be provided\n" - << HelpCatalog::description_for("load").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("load").value_or(HelpCatalog::not_provided))); } defs_ptr defs = Defs::create(); diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp index bcfcd45f5..bbeec6b3f 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp @@ -299,9 +299,8 @@ void LogCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, Abs return; } - throw std::runtime_error( - MESSAGE("LogCmd: The arguments have not been specified correctly\n" - << HelpCatalog::description_for("log").value_or("Description not provided for this option"))); + throw std::runtime_error(MESSAGE("LogCmd: The arguments have not been specified correctly\n" + << HelpCatalog::description_for("log").value_or(HelpCatalog::not_provided))); } std::ostream& operator<<(std::ostream& os, const LogCmd& c) { diff --git a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp index 9f4d49b2e..1cdc7b5f9 100644 --- a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp @@ -304,10 +304,10 @@ void PlugCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, Ab } if (args.size() != 2) { - throw std::runtime_error(MESSAGE( - "PlugCmd: Two arguments are expected, found " - << args.size() << "\n" - << HelpCatalog::description_for("plug").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("PlugCmd: Two arguments are expected, found " + << args.size() << "\n" + << HelpCatalog::description_for("plug").value_or(HelpCatalog::not_provided) + << "\n")); } std::string sourceNode = args[0]; diff --git a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp index 068d6d0b9..b02943b9e 100644 --- a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp @@ -112,7 +112,7 @@ void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A throw std::runtime_error( MESSAGE("QueryCmd: no attribute specified: query type: " << query_type << " path+attribute: " << path_and_name << "\n" - << HelpCatalog::description_for("query").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("query").value_or(HelpCatalog::not_provided))); } } else if (query_type == "trigger") { @@ -128,7 +128,7 @@ void QueryCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, A if (attribute.empty()) { throw std::runtime_error( MESSAGE("QueryCmd: no attribute specified: query type: trigger\n" - << HelpCatalog::description_for("query").value_or("Description not provided for this option"))); + << HelpCatalog::description_for("query").value_or(HelpCatalog::not_provided))); } } else if (query_type == "state" || query_type == "dstate") { diff --git a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp index 12f0d6b9e..6e704d7b6 100644 --- a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp @@ -227,7 +227,7 @@ void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& throw std::runtime_error(MESSAGE( "RequeueNodeCmd: No paths specified. At least one path expected. Paths must begin with a leading '/' " "character\n" - << HelpCatalog::description_for("requeue").value_or("Description not provided for this option") << "\n")); + << HelpCatalog::description_for("requeue").value_or(HelpCatalog::not_provided) << "\n")); } RequeueNodeCmd::Option option = RequeueNodeCmd::NO_OPTION; @@ -248,14 +248,13 @@ void RequeueNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& else { throw std::runtime_error( MESSAGE("RequeueNodeCmd: RequeueNodeCmd: Expected : [force | abort ] paths.\n" - << HelpCatalog::description_for("requeue").value_or("Description not provided for this option") - << "\n")); + << HelpCatalog::description_for("requeue").value_or(HelpCatalog::not_provided) << "\n")); } } if (options.size() > 1) { - throw std::runtime_error(MESSAGE( - "RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" - << HelpCatalog::description_for("requeue").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("RequeueNodeCmd: Expected only a single option i.e [ force | abort ]\n" + << HelpCatalog::description_for("requeue").value_or(HelpCatalog::not_provided) + << "\n")); } cmd = std::make_shared(paths, option); diff --git a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp index ae8c48af3..af54f57ae 100644 --- a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp @@ -165,25 +165,25 @@ void RunNodeCmd::create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, std::vector options, paths; split_args_to_options_and_paths(args, options, paths); // relative order is still preserved if (paths.empty()) { - throw std::runtime_error(MESSAGE( - "RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" - << HelpCatalog::description_for("run").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error( + MESSAGE("RunNodeCmd: No paths specified. Paths must begin with a leading '/' character\n" + << HelpCatalog::description_for("run").value_or(HelpCatalog::not_provided) << "\n")); } bool force = false; if (!options.empty()) { if (options.size() != 1) { - throw std::runtime_error(MESSAGE( - "RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" - << HelpCatalog::description_for("run").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("RunNodeCmd: Invalid arguments. Expected a single optional 'force'\n" + << HelpCatalog::description_for("run").value_or(HelpCatalog::not_provided) + << "\n")); } if (options[0].find("force") != std::string::npos) { force = true; } else { - throw std::runtime_error(MESSAGE( - "RunNodeCmd: Expected force \n" - << HelpCatalog::description_for("run").value_or("Description not provided for this option") << "\n")); + throw std::runtime_error(MESSAGE("RunNodeCmd: Expected force \n" + << HelpCatalog::description_for("run").value_or(HelpCatalog::not_provided) + << "\n")); } } cmd = std::make_shared(paths, force); diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 761bcf90b..4c3cd9eb8 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -378,7 +378,7 @@ void Documentation::show_summary(std::ostream& os, PREDICATE select) const { first_line = *summary; } else { - first_line = "Description not provided for this option"; + first_line = ecf::HelpCatalog::not_provided; } os << " " << std::left << std::setw(max_width) << name << " "; @@ -427,7 +427,7 @@ void Documentation::show_command_help(std::ostream& os, const std::string& comma os << *text << "\n\n"; } else { - os << "Description not provided for this option" << "\n\n"; + os << ecf::HelpCatalog::not_provided << "\n\n"; } if (!CommandFilter::is_option(od->long_name())) { os << client_env_description; From 11011193e95e0a8ab85ba1b79b08d6c90491e6f1 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 19:41:52 +0100 Subject: [PATCH 37/49] Delete now-dead desc()/arg_desc() helpers These functions existed solely to feed text to Boost's option parser and, for some commands, thrown parser errors. Both uses were already migrated to read from the HelpCatalog manifest, leaving these as orphaned duplicates that could silently drift from it. Removing them keeps the manifest the single source of truth for command/option help. --- .../src/ecflow/base/cts/task/AbortCmd.cpp | 11 -- .../src/ecflow/base/cts/task/AbortCmd.hpp | 3 +- .../src/ecflow/base/cts/task/CompleteCmd.cpp | 13 --- .../src/ecflow/base/cts/task/CompleteCmd.hpp | 3 +- .../src/ecflow/base/cts/task/CtsWaitCmd.cpp | 7 -- .../src/ecflow/base/cts/task/CtsWaitCmd.hpp | 3 +- .../src/ecflow/base/cts/task/EventCmd.cpp | 13 --- .../src/ecflow/base/cts/task/EventCmd.hpp | 3 +- .../base/src/ecflow/base/cts/task/InitCmd.cpp | 13 --- .../base/src/ecflow/base/cts/task/InitCmd.hpp | 3 +- .../src/ecflow/base/cts/task/LabelCmd.cpp | 12 -- .../src/ecflow/base/cts/task/LabelCmd.hpp | 3 +- .../src/ecflow/base/cts/task/MeterCmd.cpp | 11 -- .../src/ecflow/base/cts/task/MeterCmd.hpp | 3 +- .../src/ecflow/base/cts/task/QueueCmd.cpp | 33 ------ .../src/ecflow/base/cts/task/QueueCmd.hpp | 3 +- .../src/ecflow/base/cts/user/AlterCmd.cpp | 110 ------------------ .../src/ecflow/base/cts/user/AlterCmd.hpp | 3 +- .../src/ecflow/base/cts/user/BeginCmd.cpp | 16 --- .../src/ecflow/base/cts/user/BeginCmd.hpp | 3 +- .../src/ecflow/base/cts/user/CFileCmd.cpp | 10 -- .../src/ecflow/base/cts/user/CFileCmd.hpp | 3 +- .../src/ecflow/base/cts/user/CheckPtCmd.cpp | 37 ------ libs/base/src/ecflow/base/cts/user/CtsCmd.cpp | 28 ----- .../src/ecflow/base/cts/user/CtsNodeCmd.cpp | 70 ----------- .../src/ecflow/base/cts/user/DeleteCmd.cpp | 14 --- .../ecflow/base/cts/user/EditScriptCmd.cpp | 47 -------- .../ecflow/base/cts/user/EditScriptCmd.hpp | 3 +- .../src/ecflow/base/cts/user/ForceCmd.cpp | 31 ----- .../src/ecflow/base/cts/user/ForceCmd.hpp | 3 +- .../src/ecflow/base/cts/user/FreeDepCmd.cpp | 17 --- .../src/ecflow/base/cts/user/FreeDepCmd.hpp | 3 +- .../src/ecflow/base/cts/user/GroupCTSCmd.cpp | 12 -- .../src/ecflow/base/cts/user/GroupCTSCmd.hpp | 3 +- .../src/ecflow/base/cts/user/LoadDefsCmd.cpp | 18 --- .../src/ecflow/base/cts/user/LoadDefsCmd.hpp | 3 +- libs/base/src/ecflow/base/cts/user/LogCmd.cpp | 32 ----- libs/base/src/ecflow/base/cts/user/LogCmd.hpp | 3 +- .../ecflow/base/cts/user/LogMessageCmd.cpp | 6 - .../ecflow/base/cts/user/LogMessageCmd.hpp | 3 +- .../base/src/ecflow/base/cts/user/MoveCmd.cpp | 3 - .../base/src/ecflow/base/cts/user/MoveCmd.hpp | 3 +- .../src/ecflow/base/cts/user/OrderNodeCmd.cpp | 23 ---- .../src/ecflow/base/cts/user/OrderNodeCmd.hpp | 3 +- .../src/ecflow/base/cts/user/PathsCmd.cpp | 23 ---- .../base/src/ecflow/base/cts/user/PlugCmd.cpp | 17 --- .../base/src/ecflow/base/cts/user/PlugCmd.hpp | 3 +- .../src/ecflow/base/cts/user/QueryCmd.cpp | 59 ---------- .../src/ecflow/base/cts/user/QueryCmd.hpp | 3 +- .../ecflow/base/cts/user/ReplaceNodeCmd.cpp | 28 ----- .../ecflow/base/cts/user/ReplaceNodeCmd.hpp | 3 +- .../ecflow/base/cts/user/RequeueNodeCmd.cpp | 15 --- .../ecflow/base/cts/user/RequeueNodeCmd.hpp | 3 +- .../src/ecflow/base/cts/user/RunNodeCmd.cpp | 25 ---- .../src/ecflow/base/cts/user/RunNodeCmd.hpp | 3 +- .../ecflow/base/cts/user/ServerVersionCmd.cpp | 8 -- .../base/src/ecflow/base/cts/user/ShowCmd.cpp | 35 ------ .../base/src/ecflow/base/cts/user/ShowCmd.hpp | 3 +- 58 files changed, 26 insertions(+), 849 deletions(-) diff --git a/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp b/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp index eb4cab367..e28031bc4 100644 --- a/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/AbortCmd.cpp @@ -98,17 +98,6 @@ STC_Cmd_ptr AbortCmd::doHandleRequest(AbstractServer* as) const { const char* AbortCmd::arg() { return TaskApi::abortArg(); } -const char* AbortCmd::desc() { - return "Mark task as aborted. For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables\n" - " arg1 = (optional) string(reason)\n" - " Optionally provide a reason why the abort was raised\n\n" - "If this child command is a zombie, then the default action will be to *block*.\n" - "The default can be overridden by using zombie attributes.\n" - "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n" - "Usage:\n" - " ecflow_client --abort=reasonX"; -} void AbortCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(AbortCmd::arg(), boost::program_options::value()->implicit_value(std::string{})); diff --git a/libs/base/src/ecflow/base/cts/task/AbortCmd.hpp b/libs/base/src/ecflow/base/cts/task/AbortCmd.hpp index a24c33968..50306964f 100644 --- a/libs/base/src/ecflow/base/cts/task/AbortCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/AbortCmd.hpp @@ -36,8 +36,7 @@ class AbortCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::ABORT; } diff --git a/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp b/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp index ad5ffaf50..0a9d03e4d 100644 --- a/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/CompleteCmd.cpp @@ -82,19 +82,6 @@ STC_Cmd_ptr CompleteCmd::doHandleRequest(AbstractServer* as) const { const char* CompleteCmd::arg() { return TaskApi::completeArg(); } -const char* CompleteCmd::desc() { - return "Mark task as complete. For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables\n\n" - "If this child command is a zombie, then the default action will be to *block*.\n" - "The default can be overridden by using zombie attributes.\n" - "Otherwise the blocking period is defined by ECF_TIMEOUT.\n" - "The init command allows variables to be added, and complete command\n" - "allows for them to be removed.\n" - " arg1(--remove)(optional) = a list of variables to removed from this task\n\n" - "Usage:\n" - " ecflow_client --complete\n" - " ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task"; -} void CompleteCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CompleteCmd::arg(), "")("remove", diff --git a/libs/base/src/ecflow/base/cts/task/CompleteCmd.hpp b/libs/base/src/ecflow/base/cts/task/CompleteCmd.hpp index 26b69c77e..fe3b9cb82 100644 --- a/libs/base/src/ecflow/base/cts/task/CompleteCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/CompleteCmd.hpp @@ -39,8 +39,7 @@ class CompleteCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::COMPLETE; } diff --git a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp index 01c92fc0a..805c3f00c 100644 --- a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.cpp @@ -103,13 +103,6 @@ STC_Cmd_ptr CtsWaitCmd::doHandleRequest(AbstractServer* as) const { const char* CtsWaitCmd::arg() { return TaskApi::waitArg(); } -const char* CtsWaitCmd::desc() { - return "Evaluates an expression, and block while the expression is false.\n" - "For use in the '.ecf' file *only*, hence the context is supplied via environment variables\n" - " arg1 = string(expression)\n\n" - "Usage:\n" - " ecflow_client --wait=\"/suite/taskx == complete\""; -} void CtsWaitCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CtsWaitCmd::arg(), boost::program_options::value()); diff --git a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.hpp b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.hpp index 438207b70..d0fba9514 100644 --- a/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/CtsWaitCmd.hpp @@ -38,8 +38,7 @@ class CtsWaitCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::WAIT; } diff --git a/libs/base/src/ecflow/base/cts/task/EventCmd.cpp b/libs/base/src/ecflow/base/cts/task/EventCmd.cpp index e4a94dab5..27de85934 100644 --- a/libs/base/src/ecflow/base/cts/task/EventCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/EventCmd.cpp @@ -87,19 +87,6 @@ STC_Cmd_ptr EventCmd::doHandleRequest(AbstractServer* as) const { const char* EventCmd::arg() { return TaskApi::eventArg(); } -const char* EventCmd::desc() { - return "Change event. For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables\n" - " arg1(string | int) = event-name\n\n" - " arg2(string)(optional) = [ set | clear] default value is set\n\n" - "If this child command is a zombie, then the default action will be to *fob*,\n" - "i.e allow the ecflow client command to complete without an error\n" - "The default can be overridden by using zombie attributes.\n\n" - "Usage:\n" - " ecflow_client --event=ev # set the event, default since event initial value is clear\n" - " ecflow_client --event=ev set # set the event, explicit\n" - " ecflow_client --event=ev clear # clear the event, use when event initial value is set\n"; -} void EventCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(EventCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/task/EventCmd.hpp b/libs/base/src/ecflow/base/cts/task/EventCmd.hpp index f8115b51b..07380025a 100644 --- a/libs/base/src/ecflow/base/cts/task/EventCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/EventCmd.hpp @@ -42,8 +42,7 @@ class EventCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::EVENT; } diff --git a/libs/base/src/ecflow/base/cts/task/InitCmd.cpp b/libs/base/src/ecflow/base/cts/task/InitCmd.cpp index fec798180..0649cd739 100644 --- a/libs/base/src/ecflow/base/cts/task/InitCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/InitCmd.cpp @@ -80,19 +80,6 @@ STC_Cmd_ptr InitCmd::doHandleRequest(AbstractServer* as) const { const char* InitCmd::arg() { return TaskApi::initArg(); } -const char* InitCmd::desc() { - return "Mark task as started(active). For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables.\n" - " arg1(string) = process_or_remote_id The process id of the job or remote_id\n" - " Using remote id allows the jobs to be killed\n" - " arg2(--add)(optional)= add/update variables as name value pairs\n\n" - "If this child command is a zombie, then the default action will be to *block*.\n" - "The default can be overridden by using zombie attributes.\n" - "Otherwise the blocking period is defined by ECF_TIMEOUT.\n\n" - "Usage:\n" - " ecflow_client --init=$$\n" - " ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task"; -} void InitCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(InitCmd::arg(), boost::program_options::value())( diff --git a/libs/base/src/ecflow/base/cts/task/InitCmd.hpp b/libs/base/src/ecflow/base/cts/task/InitCmd.hpp index db9b087cc..acc513417 100644 --- a/libs/base/src/ecflow/base/cts/task/InitCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/InitCmd.hpp @@ -40,8 +40,7 @@ class InitCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::INIT; } diff --git a/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp b/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp index 6b154bb53..dfcef1f77 100644 --- a/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/LabelCmd.cpp @@ -83,18 +83,6 @@ STC_Cmd_ptr LabelCmd::doHandleRequest(AbstractServer* as) const { const char* LabelCmd::arg() { return TaskApi::labelArg(); } -const char* LabelCmd::desc() { - return "Change Label. For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables\n" - " arg1 = label-name\n" - " arg2 = The new label value\n" - " The labels values can be single or multi-line(space separated quoted strings)\n\n" - "If this child command is a zombie, then the default action will be to *fob*,\n" - "i.e allow the ecflow client command to complete without an error\n" - "The default can be overridden by using zombie attributes.\n\n" - "Usage:\n" - " ecflow_client --label=progressed merlin"; -} void LabelCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(LabelCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/task/LabelCmd.hpp b/libs/base/src/ecflow/base/cts/task/LabelCmd.hpp index cc59217b5..fe001da59 100644 --- a/libs/base/src/ecflow/base/cts/task/LabelCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/LabelCmd.hpp @@ -41,8 +41,7 @@ class LabelCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::LABEL; } diff --git a/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp b/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp index eed87883f..6fd9711af 100644 --- a/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/MeterCmd.cpp @@ -100,17 +100,6 @@ STC_Cmd_ptr MeterCmd::doHandleRequest(AbstractServer* as) const { const char* MeterCmd::arg() { return TaskApi::meterArg(); } -const char* MeterCmd::desc() { - return "Change meter. For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables\n" - " arg1(string) = meter-name\n" - " arg2(int) = the new meter value\n\n" - "If this child command is a zombie, then the default action will be to *fob*,\n" - "i.e allow the ecflow client command to complete without an error\n" - "The default can be overridden by using zombie attributes.\n\n" - "Usage:\n" - " ecflow_client --meter=my_meter 20"; -} void MeterCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(MeterCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/task/MeterCmd.hpp b/libs/base/src/ecflow/base/cts/task/MeterCmd.hpp index 0f09f5e27..52935abd7 100644 --- a/libs/base/src/ecflow/base/cts/task/MeterCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/MeterCmd.hpp @@ -41,8 +41,7 @@ class MeterCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::METER; } diff --git a/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp b/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp index d87861f5d..ebecdb82b 100644 --- a/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp +++ b/libs/base/src/ecflow/base/cts/task/QueueCmd.cpp @@ -170,39 +170,6 @@ std::string QueueCmd::handle_queue(QueueAttr& queue_attr) const { const char* QueueCmd::arg() { return TaskApi::queue_arg(); } -const char* QueueCmd::desc() { - return "QueueCmd. For use in the '.ecf' script file *only*\n" - "Hence the context is supplied via environment variables\n" - " arg1(string) = queue-name:\n" - " arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ]\n" - " active: returns the first queued/aborted step, the return string is the queue value from the " - "definition\n" - " no_of_aborted: returns number of aborted steps as a string, i.e 10\n" - " reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors\n" - " arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active)\n" - " This is only valid for complete and aborted steps\n" - " arg4(string) = path: (optional). The path where the queue is defined.\n" - " By default we search for the queue up the node tree.\n\n" - "If this child command is a zombie, then the default action will be to *block*,\n" - "The default can be overridden by using zombie attributes." - "If the path to the queue is not defined, then this command will\n" - "search for the queue up the node hierarchy. If no queue found, command fails\n\n" - "Usage:\n" - "step=\"\"\n" - "QNAME=\"my_queue_name\"\n" - "while [1 == 1 ] ; do\n" - " # this return the first queued/aborted step, then increments to next step, return when all steps " - "processed\n" - " step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n" - " if [[ $step == \"\" ]] ; then\n" - " break;\n" - " fi\n" - " ...\n" - " ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\n" - "done\n" - "\n" - "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }\n"; -} void QueueCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(QueueCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/task/QueueCmd.hpp b/libs/base/src/ecflow/base/cts/task/QueueCmd.hpp index 699c12014..b70bcbe0e 100644 --- a/libs/base/src/ecflow/base/cts/task/QueueCmd.hpp +++ b/libs/base/src/ecflow/base/cts/task/QueueCmd.hpp @@ -49,8 +49,7 @@ class QueueCmd final : public TaskCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; ecf::Child::CmdType child_type() const override { return ecf::Child::QUEUE; } diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp index 65b4037a0..edaca87e6 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.cpp @@ -617,116 +617,6 @@ STC_Cmd_ptr AlterCmd::doHandleRequest(AbstractServer* as) const { const char* AlterCmd::arg() { return CtsApi::alterArg(); } -const char* AlterCmd::desc() { - - return - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8//////////9 - "Alter the node according to the options.\n" - "\n" - "arg1 = [ delete | change | add | set_flag | clear_flag | sort ]\n" - "\n" - "arg2 = For delete:\n" - " [ variable | time | today | date | day | cron | event | meter | late | generic |\n" - " queue | label | trigger | complete | repeat | limit | inlimit | limit_path |\n" - " zombie | aviso | mirror ]\n" - "\n" - " For change:\n" - " [ variable | clock_type | clock_gain | clock_date | clock_sync | event | meter |\n" - " label | trigger | complete | repeat | limit_max | limit_value | defstatus |\n" - " late | time | today | aviso | mirror ]\n" - "\n" - " For add:\n" - " [ variable | time | today | date | day | zombie | event | meter | late | limit |\n" - " inlimit | label | aviso | mirror ]\n" - "\n" - " For set_flag or clear_flag:\n" - " [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed |\n" - " statuscmd_failed | killcmd_failed | no_script | killed | status | late |\n" - " message complete | queue_limit | task_waiting | locked | zombie | archived |\n" - " restored | threshold | log_error | checkpt_error ]\n" - "\n" - " For sort:\n" - " [ event | meter | label | variable| limit | all ]\n" - "\n" - "arg3 = [ | ]\n" - "\n" - "arg4 = \n" - "\n" - "arg5 = ( (...)) - at least one node path required.\n" - "\n" - "*Important Notes*\n" - "\n" - " * All paths must start with a leading '/' character.\n" - "\n" - " * To update, create or remove server variables use '/' for path.\n" - "\n" - " * When updating unnamed attributes (Repeat, Trigger, Complete, ...) the name/arg3 is not necessary.\n" - "\n" - " * After changing the clock the suite needs to be re-queued for the change to take effect.\n" - "\n" - " * When adding or updating node attributes (e.g. variable, meter, event, label, limits, late)\n" - " the name (arg3) and value (arg4) must be quoted.\n" - "\n" - " * When sorting attributes, 'recursive' can be used as the value (arg3).\n" - "\n" - " * When adding a meter, the value (arg4) is expected to be a comma-separated triplet\n" - " of numerical values the form \",,\" (n.b. no spaces are allowed).\n" - "\n" - " * When adding an event, the non-optional value (arg4) must be either \"set\" or \"clear\".\n" - "\n" - " * When adding or updating aviso and mirror attributes, the value (arg4) is expected to be\n" - " a quoted list of configuration options. For example:\n" - " * for aviso, \"--remote_path /s1/f1/t2 --remote_host host --polling 20 --remote_port 3141 --ssl)\"\n" - " * for mirror, \"--listener '{ \\\"event\\\": \\\"mars\\\", \\\"request\\\": { \\\"class\\\": \"od\" } " - "}'\n" - " --url http://aviso/ --schema /path/to/schema --polling 60\"\n" - "\n" - " * For both aviso and mirror, the special value \"reload\" forces reloading the configuration.\n" - " This is typically useful after updating variables used to configure these kind of attributes.\n" - "\n" - "Usage:\n" - "\n" - " ecflow_client --alter=add variable \"value\" / # add server variable\n" - " ecflow_client --alter=add variable \"value\" /path/to/node # add node variable\n" - "\n" - " ecflow_client --alter=add time \"+00:20\" /path/to/node\n" - "\n" - " ecflow_client --alter=add date \"01.*.*\" /path/to/node\n" - "\n" - " ecflow_client --alter=add day \"sunday\" /path/to/node\n" - "\n" - " ecflow_client --alter=add label \"label_value\" /path/to/node\n" - "\n" - " ecflow_client --alter=add event \"set\"|\"clear\" /path/to/node\n" - "\n" - " ecflow_client --alter=add meter \",,value\" /path/to/node\n" - "\n" - " ecflow_client --alter=add late \"-s 00:01 -a 14:30 -c +00:01\" /path/to/node\n" - "\n" - " ecflow_client --alter=add limit mars \"100\" /path/to/node\n" - "\n" - " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"10\" /path/to/node\n" - "\n" - " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-s 10\" /path/to/node\n" - "\n" - " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-n 10\" /path/to/node\n" - "\n" - " # zombie attributes have the following structure:\n" - " `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time`\n" - " zombie_type = \"user\" | \"ecf\" | \"path\" | \"ecf_pid\" | \"ecf_passwd\" | \"ecf_pid_passwd\"\n" - " client_side_action = \"fob\" | \"fail\" | \"block\"\n" - " server_side_action = \"adopt\" | \"delete\" | \"kill\"\n" - " child = \"init\" | \"event\" | \"meter\" | \"label\" | \"wait\" | \"abort\" | \"complete\" " - "| \"queue\"\n" - " zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60\n" - "\n" - " ecflow_client --alter=add zombie \"ecf:fail::\" /path/to/node # ask system zombies to fail\n" - " ecflow_client --alter=add zombie \"user:fail::\" /path/to/node # ask user generated zombies to fail\n" - " ecflow_client --alter=add zombie \"path:fail::\" /path/to/node # ask path zombies to fail\n" - "\n" - " ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED\n" - " ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode\n"; -} void AlterCmd::addOption(boost::program_options::options_description& desc) const { // Important: this option is, in practice, multi-token (and thus should use diff --git a/libs/base/src/ecflow/base/cts/user/AlterCmd.hpp b/libs/base/src/ecflow/base/cts/user/AlterCmd.hpp index 737444d36..122f3cfeb 100644 --- a/libs/base/src/ecflow/base/cts/user/AlterCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/AlterCmd.hpp @@ -175,8 +175,7 @@ class AlterCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; STC_Cmd_ptr alter_server_state(AbstractServer*) const; diff --git a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp index 9ad749fe0..60e3e886d 100644 --- a/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/BeginCmd.cpp @@ -127,22 +127,6 @@ STC_Cmd_ptr BeginCmd::doHandleRequest(AbstractServer* as) const { const char* BeginCmd::arg() { return CtsApi::beginArg(); } -const char* BeginCmd::desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Begin playing the definition in the server.\n" - "Expects zero or a single quoted string.\n" - " arg1 = suite-name | Nothing | force\n" - " play the chosen suite, if no arg specified, play all suites, in the definition\n" - " force means reset the begin status on the suites and bypass checks.\n" - " This is only required if suite-name is provide as the first argument\n" - " Using force can cause the creation of zombies\n" - "Usage:\n" - "--begin # will begin all suites\n" - "--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be " - "quoted\n" - "--begin=\"mySuite\" # begin playing suite of name 'mySuite'\n" - "--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check"; -} void BeginCmd::addOption(boost::program_options::options_description& desc) const { // allow options like diff --git a/libs/base/src/ecflow/base/cts/user/BeginCmd.hpp b/libs/base/src/ecflow/base/cts/user/BeginCmd.hpp index 4e6e81e58..712adcc3b 100644 --- a/libs/base/src/ecflow/base/cts/user/BeginCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/BeginCmd.hpp @@ -38,8 +38,7 @@ class BeginCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp index 3d223655a..e4f01391c 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.cpp @@ -334,16 +334,6 @@ STC_Cmd_ptr CFileCmd::doHandleRequest(AbstractServer* as) const { const char* CFileCmd::arg() { return CtsApi::fileArg(); } -const char* CFileCmd::desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ]\n" - "By default will return the script.\n" - " arg1 = path to node\n" - " arg2 = (optional) [ script | job | jobout | manual | kill | stat ]\n" - " kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill\n" - " stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat\n" - " arg3 = (optional) max_lines = 10000 "; -} void CFileCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CFileCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/CFileCmd.hpp b/libs/base/src/ecflow/base/cts/user/CFileCmd.hpp index 6e07bcfca..d90ce22f4 100644 --- a/libs/base/src/ecflow/base/cts/user/CFileCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/CFileCmd.hpp @@ -48,8 +48,7 @@ class CFileCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp index 0bda3e6c2..dbabcea5d 100644 --- a/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CheckPtCmd.cpp @@ -93,43 +93,6 @@ STC_Cmd_ptr CheckPtCmd::doHandleRequest(AbstractServer* as) const { return PreAllocatedReply::ok_cmd(); } -static const char* arg_desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - - return "Forces the definition file in the server to be written to disk *or* allow mode,\n" - "interval and alarm to be changed.\n" - "Whenever the check pt file is written to disk, it is measured.\n" - "If the time to save to disk is greater than the default of 30 seconds,\n" - "then an alarm is raised. This can be seen in the GUI as a late flag on the server.\n" - "Once the late flag has been set it will need to manually cleared in the GUI\n" - "or by using --alter functionality\n" - "Note excessive save times can interfere with job scheduling.\n" - "The alarm threshold can be changed. See below.\n" - " arg1 = (optional) mode [ never | on_time | on_time: | always | ]\n" - " never : Never check point the definition in the server\n" - " on_time : Turn on automatic check pointing at interval stored on server\n" - " on_time : Turn on automatic check point, with the specified interval in seconds\n" - " alarm : Modify the alarm notification time for check pt saving to disk\n" - " always : Check point at any change in node tree, *NOT* recommended for large definitions\n" - " : This specifies the interval in seconds when server should automatically check pt.\n" - " This will only take effect of mode is on_time/CHECK_ON_TIME\n" - " Should ideally be a value greater than 60 seconds, default is 120 seconds\n" - "Usage:\n" - " --check_pt\n" - " Immediately check point the definition held in the server\n" - " --check_pt=never\n" - " Switch off check pointing\n" - " --check_pt=on_time\n" - " Start automatic check pointing at the interval stored in the server\n" - " --check_pt=180\n" - " Change the check pt interval to 180 seconds\n" - " --check_pt=on_time:90\n" - " Change mode and interval, to automatic check pointing every 90 seconds\n" - " --check_pt=alarm:35\n" - " Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds\n" - " set the late flag on the server."; -} - void CheckPtCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CtsApi::checkPtDefsArg(), boost::program_options::value()->implicit_value(std::string{})); diff --git a/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp b/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp index f1b8fb987..60a697bfd 100644 --- a/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CtsCmd.cpp @@ -442,34 +442,6 @@ STC_Cmd_ptr CtsCmd::doHandleRequest(AbstractServer* as) const { return PreAllocatedReply::ok_cmd(); } -static const char* server_load_desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Generates gnuplot files that show the server load graphically.\n" - "This is done by parsing the log file. If no log file is provided,\n" - "then the log file path is obtained from the server. If the returned\n" - "log file path is not accessible an error is returned\n" - "This command produces a three files in the CWD.\n" - " o ..gnuplot.dat\n" - " o ..gnuplot.script\n" - " o ..png\n\n" - "The generated script can be manually changed, to see different rendering\n" - "effects. i.e. just run 'gnuplot ..gnuplot.script'\n\n" - " arg1 = path to log file\n\n" - "If the path to log file is known, it is *preferable* to use this,\n" - "rather than requesting the log path from the server.\n\n" - "Usage:\n" - " --server_load=/path/to_log_file # Parses log and generate gnuplot files\n" - " --server_load # Log file path is requested from server\n" - " # which is then used to generate gnuplot files\n" - " # *AVOID* if log file path is accessible\n\n" - "Now use any png viewer to see the output i.e\n\n" - "> display ..png\n" - "> feh ..png\n" - "> eog ..png\n" - "> xdg-open ..png\n" - "> w3m ..png\n"; -} - void CtsCmd::addOption(boost::program_options::options_description& desc) const { switch (api_) { case CtsCmd::GET_ZOMBIES: { diff --git a/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp index 54f7a01a5..cc3a9fed2 100644 --- a/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/CtsNodeCmd.cpp @@ -253,76 +253,6 @@ STC_Cmd_ptr CtsNodeCmd::doHandleRequest(AbstractServer* as) const { // return do_authenticate(as, cmd, absNodePath_); // } -static const char* job_gen_only_desc() { - return "Test hierarchical Job generation only, for chosen Node.\n" - "The jobs are generated independent of the dependencies\n" - "This will generate the jobs *only*, i.e. no job submission. Used for checking job generation only\n" - " arg = node path | arg = NULL\n" - " If no node path specified generates for all Tasks in the definition. For Test only"; -} - -static const char* job_gen_desc() { // dependency_dependent_job_submission - return "Job submission for chosen Node *based* on dependencies.\n" - "The server traverses the node tree every 60 seconds, and if the dependencies are free\n" - "does job generation and submission. Sometimes the user may free time/date dependencies\n" - "to avoid waiting for the server poll, this commands allows early job generation\n" - " arg = node path | arg = NULL\n" - " If no node path specified generates for full definition."; -} - -static const char* why_desc() { - return "Show the reason why a node is not running.\n" - "Can only be used with the group command. The group command must include a \n" - "'get' command(i.e returns the server defs)\n" - "The why command take a optional string argument representing a node path\n" - "Will return reason why the node is holding and for all its children.\n" - "If no arguments supplied will report on all nodes\n" - " arg = node path | arg = NULL\n" - "Usage:\n" - " --group=\"get; why\" # returns why for all holding nodes\n" - " --group=\"get; why=/suite/family\" # returns why for a specific node"; -} - -static const char* get_desc() { - return "Get the suite definition or node tree in form that is re-parse able\n" - "Get all suite node tree's from the server and write to standard out.\n" - "The output is parse-able, and can be used to re-load the definition\n" - " arg = NULL | arg = node path\n" - "Usage:\n" - " --get # gets the definition from the server,and writes to standard out\n" - " --get=/s1 # gets the suite from the server,and writes to standard out"; -} - -static const char* get_state_desc() { - return "Get state data. For the whole suite definition or individual nodes.\n" - "This will include event, meter, node state, trigger and time state.\n" - "The output is written to standard out.\n" - " arg = NULL | arg = node path\n" - "Usage:\n" - " --get_state # gets the definition from the server,and writes to standard out\n" - " --get_state=/s1 # gets the suite from the server,and writes to standard out"; -} - -const char* migrate_desc() { - return "Used to print state of the definition returned from the server to standard output.\n" - "The node state is shown in the comments.\n" - "This is the format used in the check point file, but with indentation.\n" - "Since this is essentially the defs format with state in the comments," - "it allows the definition to be migrated to future version of ecflow.\n" - "The output includes edit history but excludes externs.\n" - "When the definition is reloaded *NO* checking is done.\n" - "\n" - "The following shows a summary of the features associated with each choice:\n" - " --get --get_state --migrate\n" - "Auto generate externs Yes Yes No\n" - "Checking on reload Yes Yes No\n" - "Edit History No No Yes\n" - "Show trigger AST No Yes No\n\n" - "Usage:\n" - " --migrate # show all suites\n" - " --migrate=/s1 # show state for suite s1\n"; -} - void CtsNodeCmd::addOption(boost::program_options::options_description& desc) const { switch (api_) { case CtsNodeCmd::GET: { diff --git a/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp b/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp index 996390f17..66bd18a92 100644 --- a/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/DeleteCmd.cpp @@ -165,20 +165,6 @@ void DeleteCmd::check_for_active_or_submitted_tasks(AbstractServer* as, Node* th } } -static const char* delete_node_desc() { - return "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.\n" - " arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted " - "tasks\n" - " arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt\n" - " arg3 = node paths | _all_ # _all_ means delete all suites\n" - " # node paths must start with a leading '/'\n" - "Usage:\n" - " --delete=_all_ # Delete all suites in server. Use with care.\n" - " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt\n" - " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted\n" - " --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt"; -} - void DeleteCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CtsApi::delete_node_arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp index 52673e5c4..7bac79ac7 100644 --- a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.cpp @@ -292,53 +292,6 @@ STC_Cmd_ptr EditScriptCmd::doHandleRequest(AbstractServer* as) const { const char* EditScriptCmd::arg() { return CtsApi::edit_script_arg(); } -const char* EditScriptCmd::desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Allows user to edit, pre-process and submit the script.\n" - "Will allow pre-processing of arbitrary file with 'pre_process_file' option\n" - " arg1 = path to task # The path to the task/alias\n" - " arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ]\n" - " edit : will return the script file to standard out. The script will\n" - " include used variables enclosed between %comment/%end at the\n" - " start of the file\n" - " pre_process: Will return the script file to standard out.The script will\n" - " include used variables enclosed between %comment/%end at the\n" - " start of the file and with all %include expanded\n" - " submit: Will extract the used variables from the supplied file, i.e\n" - " between the %comment/%end and use these them to generate the\n" - " job using the ecf file accessible from the server\n" - " pre_process_file: Will pre process the user supplied file.\n" - " Will expand includes,variable substitution,\n" - " remove manual & comment sections.\n" - " submit_file: Like submit, but the supplied file, is submitted by the server\n" - " The last 2 options allow complete freedom to debug the script file\n" - " arg3 = [ path_to_script_file ]\n" - " needed for option [ pre_process_file | submit_file ]\n" - " arg4 = create_alias (optional) default value is false, for use with 'submit_file' option\n" - " arg5 = no_run (optional) default value is false, i.e immediately run the alias\n" - " is no_run is specified the alias in only created\n" - "Usage:\n" - "--edit_script=/path/to/task edit > script_file\n" - " server returns script with the used variables to standard out\n" - " The user can choose to edit this file\n\n" - "--edit_script=/path/to/task pre_process > pre_processed_script_file\n" - " server will pre process the ecf file accessible from the server\n" - " (i.e expand all %includes) and return the file to standard out\n\n" - "--edit_script=/path/to/task submit script_file\n" - " Will extract the used variables in the 'script_file' and will uses these\n" - " variables during variable substitution of the ecf file accessible by the\n" - " server. This is then submitted as a job\n\n" - "--edit_script=/path/to/task pre_process_file file_to_pre_process\n" - " The server will pre-process the user supplied file and return the contents\n" - " to standard out. This pre-processing is the same as job file processing,\n" - " but on a arbitrary file\n\n" - "--edit_script=/path/to/task submit_file file_to_submit\n" - " Will extract the used variables in the 'file_to_submit' and will uses these\n" - " variables during variable substitution, the file is then submitted for job\n" - " generation by the server\n\n" - "--edit_script=/path/to/task submit_file file_to_submit create_alias\n" - " Like the the previous example but will create and run as an alias"; -} void EditScriptCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(EditScriptCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.hpp b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.hpp index 8ad110f32..8ab92a527 100644 --- a/libs/base/src/ecflow/base/cts/user/EditScriptCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/EditScriptCmd.hpp @@ -69,8 +69,7 @@ class EditScriptCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp index e51bf0de0..665aa99b0 100644 --- a/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ForceCmd.cpp @@ -209,37 +209,6 @@ STC_Cmd_ptr ForceCmd::doHandleRequest(AbstractServer* as) const { const char* ForceCmd::arg() { return CtsApi::forceArg(); } -const char* ForceCmd::desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Force a node to a given state, or set its event.\n" - "When a task is set to complete, it may be automatically re-queued if it has\n" - "multiple future time dependencies. However each time we force a complete it will\n" - "expire any time based attribute on that node. When the last time based attribute\n" - "expires, the node will stay in a complete state.\n" - "This behaviour allow Repeat values to be incremented interactively.\n" - "A repeat attribute is incremented when all the child nodes are complete\n" - "in this case the child nodes are automatically re-queued.\n" - " arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ]\n" - " arg2 = (optional) recursive\n" - " Applies state to node and recursively to all its children\n" - " arg3 = (optional) full\n" - " Set repeat variables to last value, only works in conjunction\n" - " with recursive option\n" - " arg4 = path_to_node or path_to_node:: paths must begin with '/'\n" - "Usage:\n" - " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete\n" - " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task\n" - " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1\n" - "Effect:\n" - " Consider the effect of forcing complete when the current time is at 09:00\n" - " suite s1\n" - " task t1; time 12:00 # will complete straight away\n" - " task t2; time 10:00 13:00 01:00 # will complete on fourth attempt\n\n" - " --force=complete /s1/t1 /s1/t2\n" - " When we have a time range(i.e as shown with task t2), it is re-queued and the\n" - " next time slot is incremented for each complete, until it expires, and the task completes.\n" - " Use the Why command, to show next run time (i.e. next time slot)"; -} void ForceCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(ForceCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/ForceCmd.hpp b/libs/base/src/ecflow/base/cts/user/ForceCmd.hpp index 3d60fe6ef..644f434d1 100644 --- a/libs/base/src/ecflow/base/cts/user/ForceCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/ForceCmd.hpp @@ -56,8 +56,7 @@ class ForceCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp index 42fa6fc82..0432835b4 100644 --- a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.cpp @@ -117,23 +117,6 @@ STC_Cmd_ptr FreeDepCmd::doHandleRequest(AbstractServer* as) const { const char* FreeDepCmd::arg() { return CtsApi::freeDepArg(); } -const char* FreeDepCmd::desc() { - return "Free dependencies for a node. Defaults to triggers\n" - "After freeing the time related dependencies (i.e time,today,cron)\n" - "the next time slot will be missed.\n" - " arg1 = (optional) trigger\n" - " arg2 = (optional) all\n" - " Free trigger, date and all time dependencies\n" - " arg3 = (optional) date\n" - " Free date dependencies\n" - " arg4 = (optional) time\n" - " Free all time dependencies i.e time, day, today, cron\n" - " arg5 = List of paths. At least one required. Must start with a leading '/'\n" - "Usage:\n" - " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2\n" - " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1\n" - " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1"; -} void FreeDepCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(FreeDepCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.hpp b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.hpp index 88f2f4b62..7cc1d044a 100644 --- a/libs/base/src/ecflow/base/cts/user/FreeDepCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/FreeDepCmd.hpp @@ -63,8 +63,7 @@ class FreeDepCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp b/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp index b0214d497..ddfe94024 100644 --- a/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.cpp @@ -386,18 +386,6 @@ STC_Cmd_ptr GroupCTSCmd::doHandleRequest(AbstractServer* as) const { const char* GroupCTSCmd::arg() { return CtsApi::groupArg(); } -const char* GroupCTSCmd::desc() { - return "Allows a series of ';' separated commands to be grouped and executed as one.\n" - "Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt\n" - "provide 'yes' as an additional parameter. See example below.\n" - " arg = string\n" - "Usage:\n" - " --group=\"halt=yes; reloadwsfile; restart;\"\n" - " # halt server,bypass the confirmation prompt,\n" - " # reload white list file, restart server\n" - " --group=\"get; show\" # get server defs, and write to standard output\n" - " --group=\"get=/s1; show state\" # get suite 's1', and write state to standard output"; -} void GroupCTSCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(GroupCTSCmd::arg(), boost::program_options::value()); diff --git a/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.hpp b/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.hpp index 3e5c6d621..198331ea8 100644 --- a/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/GroupCTSCmd.hpp @@ -64,8 +64,7 @@ class GroupCTSCmd final : public UserCmd { void add_edit_history(Defs*) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing void setup_user_authentification(const std::string& user, const std::string& passwd) override; bool setup_user_authentification(AbstractClientEnv&) override; diff --git a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp index a4f156333..437ab19f6 100644 --- a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.cpp @@ -164,24 +164,6 @@ void LoadDefsCmd::print_only(std::string& os) const { const char* LoadDefsCmd::arg() { return CtsApi::loadDefsArg(); } -const char* LoadDefsCmd::desc() { - return "Check and load definition or checkpoint file into server.\n" - "The loaded definition will be checked for valid trigger and complete expressions,\n" - "additionally in-limit references to limits will be validated.\n" - "If the server already has the 'suites' of the same name, then a error message is issued.\n" - "The suite's can be overwritten if the force option is used.\n" - "To just check the definition and not send to server, use 'check_only'\n" - "This command can also be used to load a checkpoint file into the server\n" - " arg1 = path to the definition file or checkpoint file\n" - " arg2 = (optional) [ force | check_only | print | stats ] # default = false for all\n" - "Usage:\n" - "--load=/my/home/exotic.def # will error if suites of same name exists\n" - "--load=/my/home/exotic.def force # overwrite suite's of same name in the server\n" - "--load=/my/home/exotic.def check_only # Just check, don't send to server\n" - "--load=/my/home/exotic.def stats # Show defs statistics, don't send to server\n" - "--load=host1.3141.check # Load checkpoint file to the server\n" - "--load=host1.3141.check print # print definition to standard out in defs format\n"; -} void LoadDefsCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(LoadDefsCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.hpp b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.hpp index a392b9bb7..9d84c896f 100644 --- a/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/LoadDefsCmd.hpp @@ -51,8 +51,7 @@ class LoadDefsCmd final : public UserCmd { AbstractClientEnv* clientEnv); private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the command as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp index bbeec6b3f..77c98a279 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.cpp @@ -186,38 +186,6 @@ STC_Cmd_ptr LogCmd::doHandleRequest(AbstractServer* as) const { const char* LogCmd::arg() { return "log"; } -const char* LogCmd::desc() { - return "Get,clear,flush or create a new log file.\n" - "The user must ensure that a valid path is specified.\n" - "Specifying '--log=get' with a large number of lines from the server,\n" - "can consume a lot of **memory**. The log file can be a very large file,\n" - "hence we use a default of 100 lines, optionally the number of lines can be specified.\n" - " arg1 = [ get | clear | flush | new | path ]\n" - " get - Outputs the log file to standard out.\n" - " defaults to return the last 100 lines\n" - " The second argument can specify how many lines to return\n" - " clear - Clear the log file of its contents.\n" - " flush - Flush and close the log file. (only temporary) next time\n" - " server writes to log, it will be opened again. Hence it best\n" - " to halt the server first\n" - " new - Flush and close the existing log file, and start using the\n" - " the path defined for ECF_LOG. By changing this variable\n" - " a new log file path can be used\n" - " Alternatively an explicit path can also be provided\n" - " in which case ECF_LOG is also updated\n" - " path - Returns the path name to the existing log file\n" - " arg2 = [ new_path | optional last n lines ]\n" - " if get specified can specify lines to get. Value must be convertible to an integer\n" - " Otherwise if arg1 is 'new' then the second argument must be a path\n" - "Usage:\n" - " --log=get # Write the last 100 lines of the log file to standard out\n" - " --log=get 200 # Write the last 200 lines of the log file to standard out\n" - " --log=clear # Clear the log file. The log is now empty\n" - " --log=flush # Flush and close log file, next request will re-open log file\n" - " --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG\n" - " --log=new # Close and flush log file, and create a new log file using ECF_LOG " - "variable\n"; -} void LogCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(LogCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/LogCmd.hpp b/libs/base/src/ecflow/base/cts/user/LogCmd.hpp index 231eb874b..f325f1dd2 100644 --- a/libs/base/src/ecflow/base/cts/user/LogCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/LogCmd.hpp @@ -42,8 +42,7 @@ class LogCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; diff --git a/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp b/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp index 55488e42f..eee754133 100644 --- a/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/LogMessageCmd.cpp @@ -56,12 +56,6 @@ STC_Cmd_ptr LogMessageCmd::doHandleRequest(AbstractServer* as) const { const char* LogMessageCmd::arg() { return CtsApi::logMsgArg(); } -const char* LogMessageCmd::desc() { - return "Writes the input string to the log file.\n" - " arg1 = string\n" - "Usage:\n" - " --msg=\"place me in the log file\""; -} void LogMessageCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(LogMessageCmd::arg(), boost::program_options::value()); diff --git a/libs/base/src/ecflow/base/cts/user/LogMessageCmd.hpp b/libs/base/src/ecflow/base/cts/user/LogMessageCmd.hpp index c741dd945..8e28092e5 100644 --- a/libs/base/src/ecflow/base/cts/user/LogMessageCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/LogMessageCmd.hpp @@ -35,8 +35,7 @@ class LogMessageCmd final : public UserCmd { private: STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing std::string msg_; diff --git a/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp b/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp index fdc8f1ec7..d8a872ff9 100644 --- a/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/MoveCmd.cpp @@ -195,9 +195,6 @@ STC_Cmd_ptr MoveCmd::doHandleRequest(AbstractServer* as) const { const char* MoveCmd::arg() { return "move"; } -const char* MoveCmd::desc() { - return "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api."; -} void MoveCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(MoveCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/MoveCmd.hpp b/libs/base/src/ecflow/base/cts/user/MoveCmd.hpp index 85dbc5c0e..a269bd71e 100644 --- a/libs/base/src/ecflow/base/cts/user/MoveCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/MoveCmd.hpp @@ -38,8 +38,7 @@ class MoveCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; diff --git a/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp index 9cea76ecd..d74e22b4c 100644 --- a/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.cpp @@ -77,29 +77,6 @@ STC_Cmd_ptr OrderNodeCmd::doHandleRequest(AbstractServer* as) const { const char* OrderNodeCmd::arg() { return CtsApi::orderArg(); } -const char* OrderNodeCmd::desc() { - return "Re-orders the nodes held by the server\n" - " arg1 = node path\n" - " arg2 = [ top | bottom | alpha | order | up | down | runtime]\n" - "It should be noted that in the absence of triggers and time/date dependencies,\n" - "the tasks are submitted in order.\n" - "This changes the order and hence affects the submission order::\n\n" - " o top raises the node within its parent, so that it is first\n" - " o bottom lowers the node within its parent, so that it is last\n" - " o alpha Arranges for all the peers of selected note to be sorted alphabetically (case-insensitive)\n" - " o order Arranges for all the peers of selected note to be sorted in reverse " - "alphabet(case-insensitive)\n" - " o up Moves the selected node up one place amongst its peers\n" - " o down Moves the selected node down one place amongst its peers\n\n" - " o runtime Orders the nodes according to state change runtime\n" - " for families by accumulated runtime of its children\n" - " useful to submit the task that take longer earlier\n\n" - "This command can fail because:\n" - "- The node path does not exist in the server\n" - "- The order_type is not does not match one of arg2\n" - "Usage:\n" - " --order=/suite/f1 top # move node f1 to the top"; -} void OrderNodeCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(OrderNodeCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.hpp b/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.hpp index 56cbd34fb..861953836 100644 --- a/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/OrderNodeCmd.hpp @@ -38,8 +38,7 @@ class OrderNodeCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp b/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp index 2d71344d9..5ece919cd 100644 --- a/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PathsCmd.cpp @@ -464,29 +464,6 @@ STC_Cmd_ptr PathsCmd::doHandleRequest(AbstractServer* as) const { // return do_authenticate(as, cmd, paths_); // } -static const char* get_check_desc() { - return "Checks the expression and limits in the server. Will also check trigger references.\n" - "Trigger expressions that reference paths that don't exist, will be reported as errors.\n" - "(Note: On the client side unresolved paths in trigger expressions must\n" - "have an associated 'extern' specified)\n" - " arg = [ _all_ | / | list of node paths ]\n" - "Usage:\n" - " --check=_all_ # Checks all the suites\n" - " --check=/ # Checks all the suites\n" - " --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1"; -} - -static const char* get_kill_desc() { - return "Kills the job associated with the node.\n" - "If a family or suite is selected, will kill hierarchically.\n" - "Kill uses the ECF_KILL_CMD variable. After variable substitution it is invoked as a command.\n" - "The command should be written in such a way that the output is written to %ECF_JOB%.kill\n" - "as this allow the --file command to report the output: .e.e.\n" - " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::\n" - "Usage::\n" - " --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2\n" - " --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1"; -} const char* get_status_desc() { return "Shows the status of a job associated with a task, in %ECF_JOB%.stat file\n" "If a family or suite is selected, will invoke status command hierarchically.\n" diff --git a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp index 1cdc7b5f9..afc2b89b3 100644 --- a/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/PlugCmd.cpp @@ -274,23 +274,6 @@ STC_Cmd_ptr PlugCmd::doHandleRequest(AbstractServer* as) const { const char* PlugCmd::arg() { return CtsApi::plugArg(); } -const char* PlugCmd::desc() { - return "Plug command is used to move nodes.\n" - "The destination node can be on another server In which case the destination\n" - "path should be of the form ':/suite/family/task\n" - " arg1 = path to source node\n" - " arg2 = path to the destination node\n" - "This command can fail because:\n" - "- Source node is in a 'active' or 'submitted' state\n" - "- Another user already has an lock\n" - "- source/destination paths do not exist on the corresponding servers\n" - "- If the destination node path is empty, i.e. only host:port is specified,\n" - " then the source node must correspond to a suite.\n" - "- If the source node is added as a child, then its name must be unique\n" - " amongst its peers\n" - "Usage:\n" - " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)"; -} void PlugCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(PlugCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/PlugCmd.hpp b/libs/base/src/ecflow/base/cts/user/PlugCmd.hpp index ca92bf731..a4c045429 100644 --- a/libs/base/src/ecflow/base/cts/user/PlugCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/PlugCmd.hpp @@ -39,8 +39,7 @@ class PlugCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; diff --git a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp index b02943b9e..739aba9e0 100644 --- a/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/QueryCmd.cpp @@ -181,65 +181,6 @@ const char* QueryCmd::arg() { return CtsApi::queryArg(); } -const char* QueryCmd::desc() { - return "Query the status of attributes\n" - " i.e state,dstate,repeat,event,meter,label,variable or trigger expression without blocking\n" - " - state return [unknown | complete | queued | aborted | submitted | active] to standard " - "out\n" - " - dstate return [unknown | complete | queued | suspended | aborted | submitted | active] to standard " - "out\n" - " - repeat returns current value as a string to standard out\n" - " - event return 'set' | 'clear' to standard out\n" - " - meter return value of the meter to standard out\n" - " - limit return current value of limit to standard out\n" - " - limit_max return limit max value to standard out\n" - " - label return new value otherwise the old value\n" - " - variable return value of the variable, repeat or generated variable to standard out,\n" - " will search up the node tree. When path is '/', the variable is looked up on the\n" - " server itself, i.e. 'ecflow_client --query variable /:name'\n" - " - trigger returns 'true' if the expression is true, otherwise 'false'\n\n" - "If this command is called within a '.ecf' script we will additionally log the task calling this command\n" - "This is required to aid debugging for excessive use of this command\n" - "The command will fail if the node path to the attribute does not exist in the definition and if:\n" - " - repeat The repeat is not found\n" - " - event The event is not found\n" - " - meter The meter is not found\n" - " - limit/limit_max The limit is not found\n" - " - label The label is not found\n" - " - variable No user or generated variable or repeat of that name found on node or its parents,\n" - " or (when path is '/') no user or server variable of that name found on the server\n" - " - trigger Trigger does not parse, or reference to nodes/attributes in the expression are not valid\n" - "Arguments:\n" - " arg1 = [ state | dstate | repeat | event | meter | label | variable | trigger | limit | limit_max ]\n" - " arg2 = | :name where name is name of a event, meter, label, limit or variable.\n" - " path '/' represents the server itself, and can only be used with 'state' or 'variable'\n" - " arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat\n\n" - "Usage:\n" - " ecflow_client --query state / # return top level state to standard " - "out\n" - " ecflow_client --query state /path/to/node # return node state to standard out\n" - " ecflow_client --query dstate /path/to/node # state that can included suspended\n" - " ecflow_client --query repeat /path/to/node # return the current value as a string\n" - " ecflow_client --query repeat /path/to/node prev # return the previous value as a " - "string\n" - " ecflow_client --query repeat /path/to/node next # return the next value as a string\n" - " ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out\n" - " ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the " - "meter to standard out\n" - " ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the " - "limit to standard out\n" - " ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit " - "to standard out\n" - " ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the " - "label to standard out\n" - " ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to " - "standard out\n" - " ecflow_client --query variable /:var_name # returns the server variable value " - "to standard out\n" - " ecflow_client --query trigger /path/to/node/with/trigger \"/suite/task == complete\" # return true if " - "expression evaluates false otherwise\n"; -} - STC_Cmd_ptr QueryCmd::doHandleRequest(AbstractServer* as) const { as->update_stats().query_++; diff --git a/libs/base/src/ecflow/base/cts/user/QueryCmd.hpp b/libs/base/src/ecflow/base/cts/user/QueryCmd.hpp index c23c3c895..84867ea03 100644 --- a/libs/base/src/ecflow/base/cts/user/QueryCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/QueryCmd.hpp @@ -44,8 +44,7 @@ class QueryCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing bool handleRequestIsTestable() const override { return false; } STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; diff --git a/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp index a185cfc5b..7e3e31823 100644 --- a/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.cpp @@ -181,34 +181,6 @@ void ReplaceNodeCmd::print_only(std::string& os) const { const char* ReplaceNodeCmd::arg() { return CtsApi::replace_arg(); } -const char* ReplaceNodeCmd::desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Replaces a node in the server, with the given path\n" - "Can also be used to add nodes in the server\n" - " arg1 = path to node\n" - " must exist in the client defs(arg2). This is also the node we want to\n" - " replace in the server\n" - " arg2 = path to client definition file\n" - " provides the definition of the new node\n" - " arg3 = (optional) [ parent | false ] (default = parent)\n" - " create parent families or suite as needed, when arg1 does not\n" - " exist in the server\n" - " arg4 = (optional) force (default = false) \n" - " Force the replacement even if it causes zombies to be created\n" - "Replace can fail if:\n" - "- The node path(arg1) does not exist in the provided client definition(arg2)\n" - "- The client definition(arg2) must be free of errors\n" - "- If the third argument is not provided, then node path(arg1) must exist in the server\n" - "- Nodes to be replaced are in active/submitted state, in which case arg4(force) can be used\n\n" - "Replace will preserve the suspended status, if this is not required please re-queue first\n" - "After replace is done, we check trigger expressions. These are reported to standard output.\n" - "It is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\n" - "Please note, you can use --check to check trigger expression and limits in the server.\n" - "For more information use --help check.\n\n" - "Usage:\n" - " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1\n" - " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted"; -} void ReplaceNodeCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(ReplaceNodeCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.hpp b/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.hpp index a67a7cde5..5d1a0eb6a 100644 --- a/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/ReplaceNodeCmd.hpp @@ -42,8 +42,7 @@ class ReplaceNodeCmd final : public UserCmd { // used in test private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp index 6e704d7b6..02b50e024 100644 --- a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.cpp @@ -187,21 +187,6 @@ STC_Cmd_ptr RequeueNodeCmd::doHandleRequest(AbstractServer* as) const { const char* RequeueNodeCmd::arg() { return CtsApi::requeueArg(); } -const char* RequeueNodeCmd::desc() { - return "Re queues the specified node(s)\n" - " If any child of the specified node(s) is in a suspended state, this state is cleared\n" - "Repeats are reset to their starting values, relative time attributes are reset.\n" - " arg1 = (optional) [ abort | force ]\n" - " abort = re-queue only aborted tasks below node\n" - " force = Force the re-queueing even if there are nodes that are active or submitted\n" - " = Checks if any tasks are in submitted or active states below the node\n" - " if so does nothing. Otherwise re-queues the node.\n" - " arg2 = list of node paths. The node paths must begin with a leading '/' character\n\n" - "Usage:\n" - " --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1\n" - " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.\n" - " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'"; -} void RequeueNodeCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(RequeueNodeCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.hpp b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.hpp index 730335150..b814a391d 100644 --- a/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/RequeueNodeCmd.hpp @@ -44,8 +44,7 @@ class RequeueNodeCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp index af54f57ae..9733f929c 100644 --- a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.cpp @@ -126,31 +126,6 @@ STC_Cmd_ptr RunNodeCmd::doHandleRequest(AbstractServer* as) const { const char* RunNodeCmd::arg() { return CtsApi::runArg(); } -const char* RunNodeCmd::desc() { - return "Ignore triggers, limits, time or date dependencies, just run the Task.\n" - "When a job completes, it may be automatically re-queued if it has a cron\n" - "or multiple time dependencies. If we have multiple time based attributes,\n" - "then each run, will expire the time.\n" - "When we run before the time, we want to avoid re-running the task then\n" - "a flag is set, so that it is not automatically re-queued.\n" - "A repeat attribute is incremented when all the child nodes are complete\n" - "in this case the child nodes are automatically re-queued.\n" - "Hence this command can be aid, in allowing a Repeat attribute to be incremented\n" - " arg1 = (optional)force\n" - " Forcibly run, even if there are nodes that are active or submitted\n" - " This can result in zombie creation\n" - " arg2 = node path(s). The paths must begin with a leading '/' character.\n" - " If the path is /suite/family will recursively run all tasks\n" - " When providing multiple paths avoid running the same task twice\n" - "Example:\n" - " --run=/suite/t1 # run task t1\n" - "Effect:\n" - " task t1; time 12:00 # will complete if run manually\n" - " task t2; time 10:00 13:00 01:00 # will run 4 times before completing\n" - " When we have a time range(i.e as shown with task t2), then next time slot\n" - " is incremented for each run, until it expires, and the task completes.\n" - " Use the Why command, to show next run time (i.e. next time slot)"; -} void RunNodeCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(RunNodeCmd::arg(), boost::program_options::value>()->multitoken()); diff --git a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.hpp b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.hpp index 80e3f0269..83ac06e00 100644 --- a/libs/base/src/ecflow/base/cts/user/RunNodeCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/RunNodeCmd.hpp @@ -45,8 +45,7 @@ class RunNodeCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing STC_Cmd_ptr doHandleRequest(AbstractServer*) const override; // bool authenticate(AbstractServer*, STC_Cmd_ptr&) const override; diff --git a/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp b/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp index dc07da7dd..865f197e5 100644 --- a/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ServerVersionCmd.cpp @@ -52,14 +52,6 @@ STC_Cmd_ptr ServerVersionCmd::doHandleRequest(AbstractServer* as) const { return PreAllocatedReply::string_cmd(Version::full()); } -static const char* arg_desc() { - /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 - return "Returns the version number of the server\n" - "Usage:\n" - " --server_version\n" - " Writes the version to standard output\n"; -} - void ServerVersionCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(CtsApi::server_version_arg(), ""); } diff --git a/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp b/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp index 731dd43e4..2b18b2e74 100644 --- a/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp +++ b/libs/base/src/ecflow/base/cts/user/ShowCmd.cpp @@ -49,41 +49,6 @@ STC_Cmd_ptr ShowCmd::doHandleRequest(AbstractServer* as) const { const char* ShowCmd::arg() { return "show"; } -const char* ShowCmd::desc() { - return "Used to print state of the definition returned from the server to standard output.\n" - "This command can *only* be used in a group command, and will only work if it is\n" - "preceded with a get command. See examples below.\n" - " arg1 = [ defs | state | migrate ] \n" - "The output of show has several options: i.e\n" - " o no arguments: With no arguments, print the definition structure to standard output\n" - " Extern's are automatically added, allowing the output to be reloaded into the server\n" - " i.e --group=\"get ; show\"\n" - " o state:\n" - " This will output definition structure along with all the state information.\n" - " This will include the trigger expressions, abstract syntax tree as comments.\n" - " Excludes the edit history\n" - " o migrate:\n" - " This will output definition structure along with all the state information.\n" - " The node state is shown in the comments.\n" - " This format allows the definition to be migrated to future version of ecflow.\n" - " The output includes edit history but excludes externs.\n" - " When the definition is reloaded *NO* checking is done.\n" - "\n" - "The following shows a summary of the features associated with each choice\n" - " DEFS STATE MIGRATE\n" - "Auto generate externs Yes Yes No\n" - "Checking on reload Yes Yes No\n" - "Edit History No No Yes\n" - "trigger AST No Yes No\n" - "\n" - "Usage:\n" - " --group=\"get ; show\"\n" - " --group=\"get ; show defs\" # same as the previous example\n" - " --group=\"get ; show state\" # Show all state for the node tree\n" - " --group=\"get ; show migrate\" # Shows state and allows migration\n" - " --group=\"get=/s1; show\" # show state for the node only\n" - " --group=\"get=/s1; show state\""; -} void ShowCmd::addOption(boost::program_options::options_description& desc) const { desc.add_options()(ShowCmd::arg(), boost::program_options::value()->implicit_value(std::string{})); diff --git a/libs/base/src/ecflow/base/cts/user/ShowCmd.hpp b/libs/base/src/ecflow/base/cts/user/ShowCmd.hpp index 2949421e8..688207c75 100644 --- a/libs/base/src/ecflow/base/cts/user/ShowCmd.hpp +++ b/libs/base/src/ecflow/base/cts/user/ShowCmd.hpp @@ -37,8 +37,7 @@ class ShowCmd final : public UserCmd { void create(Cmd_ptr& cmd, boost::program_options::variables_map& vm, AbstractClientEnv* clientEnv) const override; private: - static const char* arg(); // used for argument parsing - static const char* desc(); // The description of the argument as provided to user + static const char* arg(); // used for argument parsing // The Show Cmd is processed on the client side, // Likewise the doHandleRequest does nothing, From 5f6a82d9029aa4625e9a16aaff11f925d83f9b7f Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 20:06:21 +0100 Subject: [PATCH 38/49] Replace the hardcoded table of env vars in Help.cpp To make HelpCatalog the sole source of help information, replace the hardcoded table with a runtime query of the catalogue. --- libs/client/src/ecflow/client/Help.cpp | 162 ++++++------------------- 1 file changed, 37 insertions(+), 125 deletions(-) diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 4c3cd9eb8..92b556b2c 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -51,120 +51,31 @@ struct CommandFilter known_options{"add", "debug", "host", "password", "port", "rid", "ssl", "user", "http", "https"}; }; -struct EnvironmentOptionDocs -{ - std::string kind; // "option", "task", "both" - std::string name; - std::string type; - std::string required; - std::string description; -}; - -std::vector known_env_options = { - // clang-format off - { - "both", - "ECF_HOST", - "string", - "mandatory*", - "The main server hostname; default value is 'localhost'" - }, - { - "both", - "ECF_PORT", - "int", - "mandatory*", - "The main server port; default value is '3141'" - }, -#ifdef ECF_OPENSSL - { - "both", - "ECF_SSL", - "any", - "optional*", - "Enable secure communication between client and server." - }, -#endif - { - "both", - "ECF_HOSTFILE", - "string", - "optional", - "File that lists alternate hosts to try, if connection to main host fails" - }, - { - "both", - "ECF_HOSTFILE_POLICY", - "string", - "optional", - "The policy ('task' or 'all') to define which commands consider using alternate hosts." - }, - { - "task", - "ECF_NAME", - "string", - "mandatory", "Full path name to the task" - }, - { - "task", - "ECF_PASS", - "string", - "mandatory", - "The job password (defined by the server, and used to authenticate client requests)" - }, - { - "task", - "ECF_TRYNO", - "int", - "mandatory", - "The run number of the job (defined by the server, and used in job/output file name generation." - }, - { - "task", - "ECF_RID", - "string", - "mandatory", - "The process identifier. Supports identifying zombies and automated killing of running jobs" - }, - { - "task", - "ECF_TIMEOUT", - "int", - "optional", - "Maximum time in *seconds* for client to deliver message to main server; default is 24 hours" - }, - { - "task", - "ECF_DENIED", - "any", - "optional", - "Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait." - }, - { - "task", - "NO_ECF", - "any", - "optional", - "If set, ecflow_client exits immediately with success; useful to test the scripts without a server" +std::string format_env_var(const nlohmann::json& var) { + std::string required = var.at("required").get(); + if (var.contains("overridable_by")) { + required += "*"; } - // clang-format on -}; -auto make_client_env_description() -> auto { + std::string line = " "; + line += var.at("name").get(); + line += " <"; + line += var.at("type").get(); + line += "> ["; + line += required; + line += "]\n "; + line += var.at("description").get(); + line += "\n"; + return line; +} + +std::string make_client_env_description() { std::string help; help += "The client considers, for both user and child commands, the following environment variables:\n\n"; - for (const auto& o : known_env_options) { - if (o.kind == "both") { - help += " "; - help += o.name; - help += " <"; - help += o.type; - help += "> ["; - help += o.required; - help += "]\n "; - help += o.description; - help += "\n"; + for (const auto& var : ecf::HelpCatalog::manifest().at("environment_variables")) { + if (var.at("applies_to").get() == "both") { + help += format_env_var(var); } } @@ -175,21 +86,13 @@ auto make_client_env_description() -> auto { return help; } -auto make_task_env_description() -> auto { +std::string make_task_env_description() { std::string help; help += "The following environment variables are used specifically by child commands:\n\n"; - for (const auto& o : known_env_options) { - if (o.kind == "task") { - help += " "; - help += o.name; - help += " <"; - help += o.type; - help += "> ["; - help += o.required; - help += "]\n "; - help += o.description; - help += "\n"; + for (const auto& var : ecf::HelpCatalog::manifest().at("environment_variables")) { + if (var.at("applies_to").get() == "task") { + help += format_env_var(var); } } @@ -198,9 +101,18 @@ auto make_task_env_description() -> auto { return help; } -std::string client_env_description = make_client_env_description(); +// Lazily built and cached, matching HelpCatalog::manifest()'s own lazy parse: ecflow_client is +// invoked by a task potentially thousands of times over a suite run, and only a small fraction +// of those invocations ever request help, so this must not force a JSON parse on every one. +const std::string& client_env_description() { + static const std::string instance = make_client_env_description(); + return instance; +} -std::string client_task_env_description = make_task_env_description(); +const std::string& client_task_env_description() { + static const std::string instance = make_task_env_description(); + return instance; +} int get_options_max_width(const Help::descriptions_t& options) { size_t vec_size = options.size(); @@ -430,10 +342,10 @@ void Documentation::show_command_help(std::ostream& os, const std::string& comma os << ecf::HelpCatalog::not_provided << "\n\n"; } if (!CommandFilter::is_option(od->long_name())) { - os << client_env_description; + os << client_env_description(); if (ecf::Child::valid_child_cmd(od->long_name())) { os << "\n"; - os << client_task_env_description; + os << client_task_env_description(); } } } From b81842095b5089d616198e95ba91ba14f78503b0 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 20:13:18 +0100 Subject: [PATCH 39/49] Rename child to task in Help.cpp Rename output text throughout the CLI's --help dispatch to match the "task" terminology already used everywhere else. Update the recognized --help topic (child -> task), its summary banner, the kind column shown for task commands, and the Try: usage line that advertises it. --- libs/client/src/ecflow/client/Help.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 92b556b2c..4ab84cb6c 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -160,7 +160,7 @@ class Documentation { return "option "; } else if (CommandFilter::is_task_command(name)) { - return "child "; + return "task "; } else if (CommandFilter::is_user_command(name)) { return "user "; @@ -176,7 +176,7 @@ class Documentation { void Documentation::show(std::ostream& os, const std::string& topic) const { // WARNING!! - // This assumes that there are no user/child commands named: 'summary', 'all', 'child', 'user' + // This assumes that there are no user/task commands named: 'summary', 'all', 'task', 'user' // if (topic.empty()) { @@ -188,8 +188,8 @@ void Documentation::show(std::ostream& os, const std::string& topic) const { else if (topic == "summary") { show_all_commands_summary(os, "\nEcflow client commands:\n"); } - else if (topic == "child") { - show_task_commands_summary(os, "\nEcflow child client commands:\n"); + else if (topic == "task") { + show_task_commands_summary(os, "\nEcflow task client commands:\n"); } else if (topic == "user") { show_user_commands_summary(os, "\nEcflow user client commands:\n"); @@ -210,7 +210,7 @@ void Documentation::show_help(std::ostream& os) const { os << "Try:\n\n"; os << " " << Ecf::CLIENT_NAME() << " --help=all # List all commands, verbosely\n"; os << " " << Ecf::CLIENT_NAME() << " --help=summary # One line summary of all commands\n"; - os << " " << Ecf::CLIENT_NAME() << " --help=child # One line summary of child commands\n"; + os << " " << Ecf::CLIENT_NAME() << " --help=task # One line summary of task commands\n"; os << " " << Ecf::CLIENT_NAME() << " --help=user # One line summary of user command\n"; os << " " << Ecf::CLIENT_NAME() << " --help= # Detailed help on each command\n\n"; From 2e5805c070bc402e596e81360f848cf95d3ffb87 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 20:20:08 +0100 Subject: [PATCH 40/49] Rename child commands to task commands in the env-var banner Update Help.cpp's and build.py's environment-variable banner text to say "task commands" instead of "child commands", matching the terminology used everywhere else in this migration. Regenerate the CLI docs to match, which also catches up docs/client_api/'s generated output with several already-verified renames from earlier steps that were never actually committed: the task commands' "child command" -> "task command" zombie-handling text, and step 6's help/version/remove reclassification and user.rst rendering fix. --- docs/client_api/api/abort.rst | 6 +++--- docs/client_api/api/alter.rst | 2 +- docs/client_api/api/archive.rst | 2 +- docs/client_api/api/begin.rst | 2 +- docs/client_api/api/ch_add.rst | 2 +- docs/client_api/api/ch_auto_add.rst | 2 +- docs/client_api/api/ch_drop.rst | 2 +- docs/client_api/api/ch_drop_user.rst | 2 +- docs/client_api/api/ch_register.rst | 2 +- docs/client_api/api/ch_rem.rst | 2 +- docs/client_api/api/ch_suites.rst | 2 +- docs/client_api/api/check.rst | 2 +- docs/client_api/api/checkJobGenOnly.rst | 2 +- docs/client_api/api/check_pt.rst | 2 +- docs/client_api/api/complete.rst | 6 +++--- docs/client_api/api/debug_server_off.rst | 2 +- docs/client_api/api/debug_server_on.rst | 2 +- docs/client_api/api/delete.rst | 2 +- docs/client_api/api/edit_history.rst | 2 +- docs/client_api/api/edit_script.rst | 2 +- docs/client_api/api/event.rst | 6 +++--- docs/client_api/api/file.rst | 2 +- docs/client_api/api/force-dep-eval.rst | 2 +- docs/client_api/api/force.rst | 2 +- docs/client_api/api/free-dep.rst | 2 +- docs/client_api/api/get.rst | 2 +- docs/client_api/api/get_state.rst | 2 +- docs/client_api/api/group.rst | 2 +- docs/client_api/api/halt.rst | 2 +- docs/client_api/api/help.rst | 2 +- docs/client_api/api/init.rst | 6 +++--- docs/client_api/api/job_gen.rst | 2 +- docs/client_api/api/kill.rst | 2 +- docs/client_api/api/label.rst | 6 +++--- docs/client_api/api/load.rst | 2 +- docs/client_api/api/log.rst | 2 +- docs/client_api/api/meter.rst | 6 +++--- docs/client_api/api/migrate.rst | 2 +- docs/client_api/api/msg.rst | 2 +- docs/client_api/api/news.rst | 2 +- docs/client_api/api/order.rst | 2 +- docs/client_api/api/ping.rst | 2 +- docs/client_api/api/plug.rst | 2 +- docs/client_api/api/query.rst | 2 +- docs/client_api/api/queue.rst | 6 +++--- docs/client_api/api/reloadcustompasswdfile.rst | 2 +- docs/client_api/api/reloadpasswdfile.rst | 2 +- docs/client_api/api/reloadwsfile.rst | 2 +- docs/client_api/api/remove.rst | 2 +- docs/client_api/api/replace.rst | 2 +- docs/client_api/api/requeue.rst | 2 +- docs/client_api/api/restart.rst | 2 +- docs/client_api/api/restore.rst | 2 +- docs/client_api/api/restore_from_checkpt.rst | 2 +- docs/client_api/api/resume.rst | 2 +- docs/client_api/api/rid.rst | 2 +- docs/client_api/api/run.rst | 2 +- docs/client_api/api/server_load.rst | 2 +- docs/client_api/api/server_version.rst | 2 +- docs/client_api/api/show.rst | 2 +- docs/client_api/api/shutdown.rst | 2 +- docs/client_api/api/stats.rst | 2 +- docs/client_api/api/stats_reset.rst | 2 +- docs/client_api/api/stats_server.rst | 2 +- docs/client_api/api/status.rst | 2 +- docs/client_api/api/suites.rst | 2 +- docs/client_api/api/suspend.rst | 2 +- docs/client_api/api/sync.rst | 2 +- docs/client_api/api/sync_clock.rst | 2 +- docs/client_api/api/sync_full.rst | 2 +- docs/client_api/api/terminate.rst | 2 +- docs/client_api/api/user.rst | 15 ++++++++++++++- docs/client_api/api/version.rst | 2 +- docs/client_api/api/wait.rst | 4 ++-- docs/client_api/api/why.rst | 2 +- docs/client_api/api/zombie_adopt.rst | 2 +- docs/client_api/api/zombie_block.rst | 2 +- docs/client_api/api/zombie_fail.rst | 2 +- docs/client_api/api/zombie_fob.rst | 2 +- docs/client_api/api/zombie_get.rst | 2 +- docs/client_api/api/zombie_kill.rst | 2 +- docs/client_api/api/zombie_remove.rst | 2 +- docs/client_api/build.py | 4 ++-- docs/client_api/cli_commands.rst | 15 --------------- docs/client_api/cli_options.rst | 14 +++++++++++++- libs/client/src/ecflow/client/Help.cpp | 4 ++-- 86 files changed, 127 insertions(+), 117 deletions(-) diff --git a/docs/client_api/api/abort.rst b/docs/client_api/api/abort.rst index cb13cec43..577b6c0bd 100644 --- a/docs/client_api/api/abort.rst +++ b/docs/client_api/api/abort.rst @@ -26,14 +26,14 @@ The following help text is generated by :code:`ecflow_client --help=abort` arg1 = (optional) string(reason) Optionally provide a reason why the abort was raised - If this child command is a zombie, then the default action will be to *block*. + If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. Otherwise the blocking period is defined by ECF_TIMEOUT. Usage: ecflow_client --abort=reasonX - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -50,7 +50,7 @@ The following help text is generated by :code:`ecflow_client --help=abort` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/alter.rst b/docs/client_api/api/alter.rst index 22ed98368..8be84df10 100644 --- a/docs/client_api/api/alter.rst +++ b/docs/client_api/api/alter.rst @@ -155,7 +155,7 @@ The following help text is generated by :code:`ecflow_client --help=alter` ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/archive.rst b/docs/client_api/api/archive.rst index 0c5b8dc8c..e71c717c8 100644 --- a/docs/client_api/api/archive.rst +++ b/docs/client_api/api/archive.rst @@ -58,7 +58,7 @@ The following help text is generated by :code:`ecflow_client --help=archive` --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2 --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/begin.rst b/docs/client_api/api/begin.rst index 9f714abff..c96eac0a2 100644 --- a/docs/client_api/api/begin.rst +++ b/docs/client_api/api/begin.rst @@ -34,7 +34,7 @@ The following help text is generated by :code:`ecflow_client --help=begin` --begin="mySuite" # begin playing suite of name 'mySuite' --begin="mySuite --force" # reset and begin playing suite 'mySuite', bypass check - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_add.rst b/docs/client_api/api/ch_add.rst index dbd1dbc60..9ae8d4a59 100644 --- a/docs/client_api/api/ch_add.rst +++ b/docs/client_api/api/ch_add.rst @@ -30,7 +30,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_add` The handle is created with --ch_register command To list all suites and handles use --ch_suites - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_auto_add.rst b/docs/client_api/api/ch_auto_add.rst index 8c7d680d3..8082bae2b 100644 --- a/docs/client_api/api/ch_auto_add.rst +++ b/docs/client_api/api/ch_auto_add.rst @@ -30,7 +30,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_auto_add` The handle is created with --ch_register command To list all suites and handles use --ch_suites - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_drop.rst b/docs/client_api/api/ch_drop.rst index 896f338b2..b4e4e7e35 100644 --- a/docs/client_api/api/ch_drop.rst +++ b/docs/client_api/api/ch_drop.rst @@ -30,7 +30,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop` The handle stored on the local client is set to zero To list all suites and handles use --ch_suites - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_drop_user.rst b/docs/client_api/api/ch_drop_user.rst index 390130bb2..93469c035 100644 --- a/docs/client_api/api/ch_drop_user.rst +++ b/docs/client_api/api/ch_drop_user.rst @@ -31,7 +31,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop_user An error is returned if no registered handles To list all suites and handles use --ch_suites - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_register.rst b/docs/client_api/api/ch_register.rst index d837ed276..a0eda12df 100644 --- a/docs/client_api/api/ch_register.rst +++ b/docs/client_api/api/ch_register.rst @@ -39,7 +39,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_register` # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first To list all suites and handles use --ch_suites - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_rem.rst b/docs/client_api/api/ch_rem.rst index 42bf73e78..9588a87bd 100644 --- a/docs/client_api/api/ch_rem.rst +++ b/docs/client_api/api/ch_rem.rst @@ -29,7 +29,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_rem` The handle is created with --ch_register command To list all suites and handles use --ch_suites - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ch_suites.rst b/docs/client_api/api/ch_suites.rst index 7d902e632..dbfc1e9f6 100644 --- a/docs/client_api/api/ch_suites.rst +++ b/docs/client_api/api/ch_suites.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_suites` Shows all the client handles, and the suites they reference - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/check.rst b/docs/client_api/api/check.rst index 8663e5c74..51c088777 100644 --- a/docs/client_api/api/check.rst +++ b/docs/client_api/api/check.rst @@ -31,7 +31,7 @@ The following help text is generated by :code:`ecflow_client --help=check` --check=/ # Checks all the suites --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/checkJobGenOnly.rst b/docs/client_api/api/checkJobGenOnly.rst index 82c387d7c..d73f3d98e 100644 --- a/docs/client_api/api/checkJobGenOnly.rst +++ b/docs/client_api/api/checkJobGenOnly.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=checkJobGenO arg = node path | arg = NULL If no node path specified generates for all Tasks in the definition. For Test only - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/check_pt.rst b/docs/client_api/api/check_pt.rst index 0e3154e11..c3c80bebc 100644 --- a/docs/client_api/api/check_pt.rst +++ b/docs/client_api/api/check_pt.rst @@ -54,7 +54,7 @@ The following help text is generated by :code:`ecflow_client --help=check_pt` Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds set the late flag on the server. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/complete.rst b/docs/client_api/api/complete.rst index a1adbd958..043aa0404 100644 --- a/docs/client_api/api/complete.rst +++ b/docs/client_api/api/complete.rst @@ -24,7 +24,7 @@ The following help text is generated by :code:`ecflow_client --help=complete` Mark task as complete. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - If this child command is a zombie, then the default action will be to *block*. + If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. Otherwise the blocking period is defined by ECF_TIMEOUT. The init command allows variables to be added, and complete command @@ -35,7 +35,7 @@ The following help text is generated by :code:`ecflow_client --help=complete` ecflow_client --complete ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -52,7 +52,7 @@ The following help text is generated by :code:`ecflow_client --help=complete` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/debug_server_off.rst b/docs/client_api/api/debug_server_off.rst index 7a32da9e1..67d6fb6c7 100644 --- a/docs/client_api/api/debug_server_off.rst +++ b/docs/client_api/api/debug_server_off.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=debug_server Disables debug output from the server - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/debug_server_on.rst b/docs/client_api/api/debug_server_on.rst index ce2b0c48e..3f00b2872 100644 --- a/docs/client_api/api/debug_server_on.rst +++ b/docs/client_api/api/debug_server_on.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=debug_server Enables debug output from the server - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/delete.rst b/docs/client_api/api/delete.rst index 51595ce9e..716e55507 100644 --- a/docs/client_api/api/delete.rst +++ b/docs/client_api/api/delete.rst @@ -32,7 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=delete` --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/edit_history.rst b/docs/client_api/api/edit_history.rst index 4fc8619de..370c98af6 100644 --- a/docs/client_api/api/edit_history.rst +++ b/docs/client_api/api/edit_history.rst @@ -28,7 +28,7 @@ The following help text is generated by :code:`ecflow_client --help=edit_history --edit_history=clear # clear/purge *ALL* edit history from all nodes. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/edit_script.rst b/docs/client_api/api/edit_script.rst index ab86c99c2..40ad08f51 100644 --- a/docs/client_api/api/edit_script.rst +++ b/docs/client_api/api/edit_script.rst @@ -71,7 +71,7 @@ The following help text is generated by :code:`ecflow_client --help=edit_script` --edit_script=/path/to/task submit_file file_to_submit create_alias Like the the previous example but will create and run as an alias - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/event.rst b/docs/client_api/api/event.rst index 737160b67..dd74304ea 100644 --- a/docs/client_api/api/event.rst +++ b/docs/client_api/api/event.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=event` arg2(string)(optional) = [ set | clear] default value is set - If this child command is a zombie, then the default action will be to *fob*, + If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error The default can be overridden by using zombie attributes. @@ -37,7 +37,7 @@ The following help text is generated by :code:`ecflow_client --help=event` ecflow_client --event=ev clear # clear the event, use when event initial value is set - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -54,7 +54,7 @@ The following help text is generated by :code:`ecflow_client --help=event` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/file.rst b/docs/client_api/api/file.rst index 8fa1d549f..ae9947b28 100644 --- a/docs/client_api/api/file.rst +++ b/docs/client_api/api/file.rst @@ -29,7 +29,7 @@ The following help text is generated by :code:`ecflow_client --help=file` stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat arg3 = (optional) max_lines = 10000 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/force-dep-eval.rst b/docs/client_api/api/force-dep-eval.rst index 53bfc47d1..9210bbaa7 100644 --- a/docs/client_api/api/force-dep-eval.rst +++ b/docs/client_api/api/force-dep-eval.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=force-dep-ev Force dependency evaluation. Used for DEBUG only. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/force.rst b/docs/client_api/api/force.rst index ef428243f..0b70fac8a 100644 --- a/docs/client_api/api/force.rst +++ b/docs/client_api/api/force.rst @@ -51,7 +51,7 @@ The following help text is generated by :code:`ecflow_client --help=force` next time slot is incremented for each complete, until it expires, and the task completes. Use the Why command, to show next run time (i.e. next time slot) - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/free-dep.rst b/docs/client_api/api/free-dep.rst index 07e335d7e..38e497fac 100644 --- a/docs/client_api/api/free-dep.rst +++ b/docs/client_api/api/free-dep.rst @@ -37,7 +37,7 @@ The following help text is generated by :code:`ecflow_client --help=free-dep` --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1 --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/get.rst b/docs/client_api/api/get.rst index fb53ebf57..52ca09fa2 100644 --- a/docs/client_api/api/get.rst +++ b/docs/client_api/api/get.rst @@ -56,7 +56,7 @@ The following help text is generated by :code:`ecflow_client --help=get` --get # gets the definition from the server,and writes to standard out --get=/s1 # gets the suite from the server,and writes to standard out - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/get_state.rst b/docs/client_api/api/get_state.rst index 980420e7f..1894a33f0 100644 --- a/docs/client_api/api/get_state.rst +++ b/docs/client_api/api/get_state.rst @@ -29,7 +29,7 @@ The following help text is generated by :code:`ecflow_client --help=get_state` --get_state # gets the definition from the server,and writes to standard out --get_state=/s1 # gets the suite from the server,and writes to standard out - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/group.rst b/docs/client_api/api/group.rst index e1f0c2d15..0589e47aa 100644 --- a/docs/client_api/api/group.rst +++ b/docs/client_api/api/group.rst @@ -32,7 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=group` --group="get; show" # get server defs, and write to standard output --group="get=/s1; show state" # get suite 's1', and write state to standard output - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/halt.rst b/docs/client_api/api/halt.rst index 277457cd7..eda31dbb0 100644 --- a/docs/client_api/api/halt.rst +++ b/docs/client_api/api/halt.rst @@ -34,7 +34,7 @@ The following help text is generated by :code:`ecflow_client --help=halt` | HALTED | yes | no | no | no | |--------------|--------------|--------------|---------------|---------------------| - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/help.rst b/docs/client_api/api/help.rst index ed8cb37fb..22a08e324 100644 --- a/docs/client_api/api/help.rst +++ b/docs/client_api/api/help.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=help` Produce help message - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/init.rst b/docs/client_api/api/init.rst index b20168598..c61d224f7 100644 --- a/docs/client_api/api/init.rst +++ b/docs/client_api/api/init.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=init` Using remote id allows the jobs to be killed arg2(--add)(optional)= add/update variables as name value pairs - If this child command is a zombie, then the default action will be to *block*. + If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. Otherwise the blocking period is defined by ECF_TIMEOUT. @@ -35,7 +35,7 @@ The following help text is generated by :code:`ecflow_client --help=init` ecflow_client --init=$$ ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -52,7 +52,7 @@ The following help text is generated by :code:`ecflow_client --help=init` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/job_gen.rst b/docs/client_api/api/job_gen.rst index 2b1c74acf..6a4a253c5 100644 --- a/docs/client_api/api/job_gen.rst +++ b/docs/client_api/api/job_gen.rst @@ -28,7 +28,7 @@ The following help text is generated by :code:`ecflow_client --help=job_gen` arg = node path | arg = NULL If no node path specified generates for full definition. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/kill.rst b/docs/client_api/api/kill.rst index 598a06982..9641cbdd2 100644 --- a/docs/client_api/api/kill.rst +++ b/docs/client_api/api/kill.rst @@ -31,7 +31,7 @@ The following help text is generated by :code:`ecflow_client --help=kill` --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2 --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/label.rst b/docs/client_api/api/label.rst index d19aa7e52..a12218bc2 100644 --- a/docs/client_api/api/label.rst +++ b/docs/client_api/api/label.rst @@ -27,14 +27,14 @@ The following help text is generated by :code:`ecflow_client --help=label` arg2 = The new label value The labels values can be single or multi-line(space separated quoted strings) - If this child command is a zombie, then the default action will be to *fob*, + If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error The default can be overridden by using zombie attributes. Usage: ecflow_client --label=progressed merlin - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -51,7 +51,7 @@ The following help text is generated by :code:`ecflow_client --help=label` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/load.rst b/docs/client_api/api/load.rst index 8083fa962..fea5289fe 100644 --- a/docs/client_api/api/load.rst +++ b/docs/client_api/api/load.rst @@ -39,7 +39,7 @@ The following help text is generated by :code:`ecflow_client --help=load` --load=host1.3141.check print # print definition to standard out in defs format - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/log.rst b/docs/client_api/api/log.rst index 2d9454692..2787fd034 100644 --- a/docs/client_api/api/log.rst +++ b/docs/client_api/api/log.rst @@ -52,7 +52,7 @@ The following help text is generated by :code:`ecflow_client --help=log` --log=new # Close and flush log file, and create a new log file using ECF_LOG variable - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/meter.rst b/docs/client_api/api/meter.rst index 7620b2594..e46eaf606 100644 --- a/docs/client_api/api/meter.rst +++ b/docs/client_api/api/meter.rst @@ -26,14 +26,14 @@ The following help text is generated by :code:`ecflow_client --help=meter` arg1(string) = meter-name arg2(int) = the new meter value - If this child command is a zombie, then the default action will be to *fob*, + If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error The default can be overridden by using zombie attributes. Usage: ecflow_client --meter=my_meter 20 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -50,7 +50,7 @@ The following help text is generated by :code:`ecflow_client --help=meter` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/migrate.rst b/docs/client_api/api/migrate.rst index b21f1b191..2f258f466 100644 --- a/docs/client_api/api/migrate.rst +++ b/docs/client_api/api/migrate.rst @@ -40,7 +40,7 @@ The following help text is generated by :code:`ecflow_client --help=migrate` --migrate=/s1 # show state for suite s1 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/msg.rst b/docs/client_api/api/msg.rst index 280787ea4..cb39d32ea 100644 --- a/docs/client_api/api/msg.rst +++ b/docs/client_api/api/msg.rst @@ -26,7 +26,7 @@ The following help text is generated by :code:`ecflow_client --help=msg` Usage: --msg="place me in the log file" - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/news.rst b/docs/client_api/api/news.rst index f6fe2f216..25a41fa83 100644 --- a/docs/client_api/api/news.rst +++ b/docs/client_api/api/news.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=news` This relies on user calling sync after news to update the locally stored modify and change numbers. These numbers are then used in the next call to news. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/order.rst b/docs/client_api/api/order.rst index 08d295b6f..3bd617183 100644 --- a/docs/client_api/api/order.rst +++ b/docs/client_api/api/order.rst @@ -45,7 +45,7 @@ The following help text is generated by :code:`ecflow_client --help=order` Usage: --order=/suite/f1 top # move node f1 to the top - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/ping.rst b/docs/client_api/api/ping.rst index f93bb272b..a9c0e4bcf 100644 --- a/docs/client_api/api/ping.rst +++ b/docs/client_api/api/ping.rst @@ -30,7 +30,7 @@ The following help text is generated by :code:`ecflow_client --help=ping` # ECF_HOST and ECF_PORT If ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/plug.rst b/docs/client_api/api/plug.rst index 8b147b448..de486b2f7 100644 --- a/docs/client_api/api/plug.rst +++ b/docs/client_api/api/plug.rst @@ -37,7 +37,7 @@ The following help text is generated by :code:`ecflow_client --help=plug` Usage: --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141) - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/query.rst b/docs/client_api/api/query.rst index 6db52a455..b9be43e39 100644 --- a/docs/client_api/api/query.rst +++ b/docs/client_api/api/query.rst @@ -169,7 +169,7 @@ The following help text is generated by :code:`ecflow_client --help=query` ecflow_client --query trigger /path/to/node/with/trigger "/suite/task == complete" # return true if expression evaluates false otherwise - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/queue.rst b/docs/client_api/api/queue.rst index 2624dda60..ace9981ee 100644 --- a/docs/client_api/api/queue.rst +++ b/docs/client_api/api/queue.rst @@ -33,7 +33,7 @@ The following help text is generated by :code:`ecflow_client --help=queue` arg4(string) = path: (optional). The path where the queue is defined. By default we search for the queue up the node tree. - If this child command is a zombie, then the default action will be to *block*, + If this task command is a zombie, then the default action will be to *block*, The default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will search for the queue up the node hierarchy. If no queue found, command fails @@ -53,7 +53,7 @@ The following help text is generated by :code:`ecflow_client --help=queue` trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed } - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -70,7 +70,7 @@ The following help text is generated by :code:`ecflow_client --help=queue` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/reloadcustompasswdfile.rst b/docs/client_api/api/reloadcustompasswdfile.rst index d24afe281..14469bf28 100644 --- a/docs/client_api/api/reloadcustompasswdfile.rst +++ b/docs/client_api/api/reloadcustompasswdfile.rst @@ -70,7 +70,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadcustom Usage: --reloadcustompasswdfile - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/reloadpasswdfile.rst b/docs/client_api/api/reloadpasswdfile.rst index 685192cd8..0ffa87f37 100644 --- a/docs/client_api/api/reloadpasswdfile.rst +++ b/docs/client_api/api/reloadpasswdfile.rst @@ -70,7 +70,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadpasswd Usage: --reloadpasswdfile - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/reloadwsfile.rst b/docs/client_api/api/reloadwsfile.rst index 9598b34b1..51d21c25c 100644 --- a/docs/client_api/api/reloadwsfile.rst +++ b/docs/client_api/api/reloadwsfile.rst @@ -63,7 +63,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadwsfile Usage: --reloadwsfile - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/remove.rst b/docs/client_api/api/remove.rst index e229ef0b1..8d1d04663 100644 --- a/docs/client_api/api/remove.rst +++ b/docs/client_api/api/remove.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=remove` remove variables i.e name name2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/replace.rst b/docs/client_api/api/replace.rst index 885f8857e..6e0f94eee 100644 --- a/docs/client_api/api/replace.rst +++ b/docs/client_api/api/replace.rst @@ -49,7 +49,7 @@ The following help text is generated by :code:`ecflow_client --help=replace` --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1 --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/requeue.rst b/docs/client_api/api/requeue.rst index 22933426f..57e9f21cc 100644 --- a/docs/client_api/api/requeue.rst +++ b/docs/client_api/api/requeue.rst @@ -36,7 +36,7 @@ The following help text is generated by :code:`ecflow_client --help=requeue` --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies. --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2' - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/restart.rst b/docs/client_api/api/restart.rst index 6a5cda3dc..d2cd62769 100644 --- a/docs/client_api/api/restart.rst +++ b/docs/client_api/api/restart.rst @@ -31,7 +31,7 @@ The following help text is generated by :code:`ecflow_client --help=restart` | HALTED | yes | no | no | no | |--------------|--------------|--------------|---------------|---------------------| - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/restore.rst b/docs/client_api/api/restore.rst index 7cc5921ff..d471438da 100644 --- a/docs/client_api/api/restore.rst +++ b/docs/client_api/api/restore.rst @@ -49,7 +49,7 @@ The following help text is generated by :code:`ecflow_client --help=restore` --restore=/s1/f1 # restore family /s1/f1 --restore=/s1 /s2 # restore suites /s1 and /s2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/restore_from_checkpt.rst b/docs/client_api/api/restore_from_checkpt.rst index a5eaf2b5e..0a2aa16ba 100644 --- a/docs/client_api/api/restore_from_checkpt.rst +++ b/docs/client_api/api/restore_from_checkpt.rst @@ -25,7 +25,7 @@ The following help text is generated by :code:`ecflow_client --help=restore_from The server must be halted and the definition in the server must be deleted first, otherwise an error is returned - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/resume.rst b/docs/client_api/api/resume.rst index 5a77f03f9..1f1b83608 100644 --- a/docs/client_api/api/resume.rst +++ b/docs/client_api/api/resume.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=resume` --resume=/s1 /s2 # resume suites /s1 and /s2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/rid.rst b/docs/client_api/api/rid.rst index 2ed988b8b..e49c53e2a 100644 --- a/docs/client_api/api/rid.rst +++ b/docs/client_api/api/rid.rst @@ -21,7 +21,7 @@ The following help text is generated by :code:`ecflow_client --help=rid` rid --- - When specified overrides the environment variable ECF_RID. Can only be used for child commands. + When specified overrides the environment variable ECF_RID. Can only be used for task commands. diff --git a/docs/client_api/api/run.rst b/docs/client_api/api/run.rst index a69bf9902..a4e56b887 100644 --- a/docs/client_api/api/run.rst +++ b/docs/client_api/api/run.rst @@ -45,7 +45,7 @@ The following help text is generated by :code:`ecflow_client --help=run` is incremented for each run, until it expires, and the task completes. Use the Why command, to show next run time (i.e. next time slot) - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/server_load.rst b/docs/client_api/api/server_load.rst index 734eb3ba1..56ee9bd5a 100644 --- a/docs/client_api/api/server_load.rst +++ b/docs/client_api/api/server_load.rst @@ -53,7 +53,7 @@ The following help text is generated by :code:`ecflow_client --help=server_load` > w3m ..png - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/server_version.rst b/docs/client_api/api/server_version.rst index 9e9afe618..ff62f5400 100644 --- a/docs/client_api/api/server_version.rst +++ b/docs/client_api/api/server_version.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=server_versi Writes the version to standard output - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/show.rst b/docs/client_api/api/show.rst index b0a18fe5e..dfa153da3 100644 --- a/docs/client_api/api/show.rst +++ b/docs/client_api/api/show.rst @@ -55,7 +55,7 @@ The following help text is generated by :code:`ecflow_client --help=show` --group="get=/s1; show" # show state for the node only --group="get=/s1; show state" - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/shutdown.rst b/docs/client_api/api/shutdown.rst index 6f7747006..6bf100188 100644 --- a/docs/client_api/api/shutdown.rst +++ b/docs/client_api/api/shutdown.rst @@ -33,7 +33,7 @@ The following help text is generated by :code:`ecflow_client --help=shutdown` | HALTED | yes | no | no | no | |--------------|--------------|--------------|---------------|---------------------| - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/stats.rst b/docs/client_api/api/stats.rst index d824a8e8b..140788fcb 100644 --- a/docs/client_api/api/stats.rst +++ b/docs/client_api/api/stats.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=stats` Returns the server statistics as a string. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/stats_reset.rst b/docs/client_api/api/stats_reset.rst index 4c7d258f7..eae6d315c 100644 --- a/docs/client_api/api/stats_reset.rst +++ b/docs/client_api/api/stats_reset.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=stats_reset` Resets the server statistics. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/stats_server.rst b/docs/client_api/api/stats_server.rst index 19f9675a9..28b10f4df 100644 --- a/docs/client_api/api/stats_server.rst +++ b/docs/client_api/api/stats_server.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=stats_server Returns the server statistics as a struct and string. For test use only. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/status.rst b/docs/client_api/api/status.rst index 77f1475c2..8774f7ce8 100644 --- a/docs/client_api/api/status.rst +++ b/docs/client_api/api/status.rst @@ -39,7 +39,7 @@ The following help text is generated by :code:`ecflow_client --help=status` --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/suites.rst b/docs/client_api/api/suites.rst index 8eecd7e97..5c700d0d1 100644 --- a/docs/client_api/api/suites.rst +++ b/docs/client_api/api/suites.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=suites` Returns the list of suites, in the order defined in the server. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/suspend.rst b/docs/client_api/api/suspend.rst index 9a897478d..0f25ddbbc 100644 --- a/docs/client_api/api/suspend.rst +++ b/docs/client_api/api/suspend.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=suspend` --suspend=/s1 /s2 # suspend suites /s1 and /s2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/sync.rst b/docs/client_api/api/sync.rst index 3a3f1873a..ecf6fcd74 100644 --- a/docs/client_api/api/sync.rst +++ b/docs/client_api/api/sync.rst @@ -28,7 +28,7 @@ The following help text is generated by :code:`ecflow_client --help=sync` Requires a client handle, change and modify number, to get the incremental changes from server. The change in server state is then and merged with the client definition. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/sync_clock.rst b/docs/client_api/api/sync_clock.rst index 6d3a130c5..3a25ad9b8 100644 --- a/docs/client_api/api/sync_clock.rst +++ b/docs/client_api/api/sync_clock.rst @@ -29,7 +29,7 @@ The following help text is generated by :code:`ecflow_client --help=sync_clock` Requires a client handle, change and modify number, to get the incremental changes from server. The change in server state is then and merged with the client definition. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/sync_full.rst b/docs/client_api/api/sync_full.rst index 704a54448..59cef6604 100644 --- a/docs/client_api/api/sync_full.rst +++ b/docs/client_api/api/sync_full.rst @@ -25,7 +25,7 @@ The following help text is generated by :code:`ecflow_client --help=sync_full` *Important* for use with c++/python interface only. Requires a client_handle. The returned definition is stored on the client. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/terminate.rst b/docs/client_api/api/terminate.rst index c77512177..eabee5eca 100644 --- a/docs/client_api/api/terminate.rst +++ b/docs/client_api/api/terminate.rst @@ -25,7 +25,7 @@ The following help text is generated by :code:`ecflow_client --help=terminate` arg1 = yes(optional) # use to bypass confirmation prompt.i.e --terminate=yes - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/user.rst b/docs/client_api/api/user.rst index 4f3ff45d2..e9eb354f7 100644 --- a/docs/client_api/api/user.rst +++ b/docs/client_api/api/user.rst @@ -2,7 +2,18 @@ .. _user_cli: user -//// +**** + + + + + + +.. rubric:: Output of :code:`--help=user` + + + +The following help text is generated by :code:`ecflow_client --help=user` :: @@ -13,3 +24,5 @@ user Specifies the user name used to contact the server. Must be used in combination with option --password. + + diff --git a/docs/client_api/api/version.rst b/docs/client_api/api/version.rst index 901a42821..77143bff9 100644 --- a/docs/client_api/api/version.rst +++ b/docs/client_api/api/version.rst @@ -23,7 +23,7 @@ The following help text is generated by :code:`ecflow_client --help=version` Show ecflow client version number, and version of the boost library used - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/wait.rst b/docs/client_api/api/wait.rst index e09461e32..1de2ab3d6 100644 --- a/docs/client_api/api/wait.rst +++ b/docs/client_api/api/wait.rst @@ -28,7 +28,7 @@ The following help text is generated by :code:`ecflow_client --help=wait` Usage: ecflow_client --wait="/suite/taskx == complete" - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' @@ -45,7 +45,7 @@ The following help text is generated by :code:`ecflow_client --help=wait` with the server, either by setting the environment variables or by specifying the command line options. - The following environment variables are used specifically by child commands: + The following environment variables are used specifically by task commands: ECF_NAME [mandatory] Full path name to the task diff --git a/docs/client_api/api/why.rst b/docs/client_api/api/why.rst index 5cea8e7a2..a2c0b1672 100644 --- a/docs/client_api/api/why.rst +++ b/docs/client_api/api/why.rst @@ -32,7 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=why` --group="get; why" # returns why for all holding nodes --group="get; why=/suite/family" # returns why for a specific node - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_adopt.rst b/docs/client_api/api/zombie_adopt.rst index 80675941a..581a4731f 100644 --- a/docs/client_api/api/zombie_adopt.rst +++ b/docs/client_api/api/zombie_adopt.rst @@ -28,7 +28,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_adopt args = list of task paths, at least one expected --zombie_adopt=/path/to/task /path/to/task2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_block.rst b/docs/client_api/api/zombie_block.rst index d549ee99b..00fcf1c94 100644 --- a/docs/client_api/api/zombie_block.rst +++ b/docs/client_api/api/zombie_block.rst @@ -29,7 +29,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_block args = list of task paths, at least one expected --zombie_block=/path/to/task /path/to/task2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_fail.rst b/docs/client_api/api/zombie_fail.rst index 7e3669c17..cb096bfb3 100644 --- a/docs/client_api/api/zombie_fail.rst +++ b/docs/client_api/api/zombie_fail.rst @@ -30,7 +30,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_fail` args = list of task paths, at least one expected --zombie_fail=/path/to/task /path/to/task2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_fob.rst b/docs/client_api/api/zombie_fob.rst index bbb9807f2..7174f9081 100644 --- a/docs/client_api/api/zombie_fob.rst +++ b/docs/client_api/api/zombie_fob.rst @@ -30,7 +30,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_fob` args = list of task paths, at least one expected --zombie_fob=/path/to/task1 /path/to/task2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_get.rst b/docs/client_api/api/zombie_get.rst index 455f1a82e..44399da20 100644 --- a/docs/client_api/api/zombie_get.rst +++ b/docs/client_api/api/zombie_get.rst @@ -24,7 +24,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_get` Returns the list of zombies from the server. Results reported to standard output. - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_kill.rst b/docs/client_api/api/zombie_kill.rst index 36ca1b442..821651787 100644 --- a/docs/client_api/api/zombie_kill.rst +++ b/docs/client_api/api/zombie_kill.rst @@ -29,7 +29,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_kill` arg = list of task paths, at least one expected --zombie_kill=/path/to/task /path/to/task2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/api/zombie_remove.rst b/docs/client_api/api/zombie_remove.rst index da1174d98..3b5db111f 100644 --- a/docs/client_api/api/zombie_remove.rst +++ b/docs/client_api/api/zombie_remove.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=zombie_remov args = list of task paths, at least one expected --zombie_remove=/path/to/task /path/to/task2 - The client considers, for both user and child commands, the following environment variables: + The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] The main server hostname; default value is 'localhost' diff --git a/docs/client_api/build.py b/docs/client_api/build.py index 5e2c404cf..3034189f5 100755 --- a/docs/client_api/build.py +++ b/docs/client_api/build.py @@ -180,7 +180,7 @@ def format_env_var(var): def render_client_env_description(env_vars): - txt = "The client considers, for both user and child commands, the following environment variables:\n\n" + txt = "The client considers, for both user and task commands, the following environment variables:\n\n" for var in env_vars: if var["applies_to"] == "both": txt += format_env_var(var) @@ -193,7 +193,7 @@ def render_client_env_description(env_vars): def render_task_env_description(env_vars): - txt = "The following environment variables are used specifically by child commands:\n\n" + txt = "The following environment variables are used specifically by task commands:\n\n" for var in env_vars: if var["applies_to"] == "task": txt += format_env_var(var) diff --git a/docs/client_api/cli_commands.rst b/docs/client_api/cli_commands.rst index 3f5ce88c8..b9c5007ec 100644 --- a/docs/client_api/cli_commands.rst +++ b/docs/client_api/cli_commands.rst @@ -128,10 +128,6 @@ Commands - :term:`user command` - Stop server communication with jobs, and new job scheduling. - * - :ref:`help_cli` - - :term:`user command` - - Produce help message - * - :ref:`init_cli` - :term:`child command` - Mark task as started(active). For use in the '.ecf' script file *only* @@ -204,10 +200,6 @@ Commands - :term:`user command` - Reload the white list file. - * - :ref:`remove_cli` - - :term:`user command` - - remove variables i.e name name2 - * - :ref:`replace_cli` - :term:`user command` - Replaces a node in the server, with the given path @@ -292,10 +284,6 @@ Commands - :term:`user command` - Terminate the server. - * - :ref:`version_cli` - - :term:`user command` - - Show ecflow client version number, and version of the boost library used - * - :ref:`wait_cli` - :term:`child command` - Evaluates an expression, and block while the expression is false. @@ -366,7 +354,6 @@ Commands get_state group halt - help init job_gen kill @@ -385,7 +372,6 @@ Commands reloadcustompasswdfile reloadpasswdfile reloadwsfile - remove replace requeue restart @@ -407,7 +393,6 @@ Commands sync_clock sync_full terminate - version wait why zombie_adopt diff --git a/docs/client_api/cli_options.rst b/docs/client_api/cli_options.rst index 72236bbcc..02431b6f8 100644 --- a/docs/client_api/cli_options.rst +++ b/docs/client_api/cli_options.rst @@ -17,6 +17,9 @@ Options * - :ref:`debug_cli` - Enables the display of client environment settings and execution details. + * - :ref:`help_cli` + - Produce help message + * - :ref:`host_cli` - When specified overrides the environment variable ECF_HOST and default host: 'localhost' @@ -32,8 +35,11 @@ Options * - :ref:`port_cli` - When specified overrides the environment variable ECF_PORT and default port: '3141' + * - :ref:`remove_cli` + - remove variables i.e name name2 + * - :ref:`rid_cli` - - When specified overrides the environment variable ECF_RID. Can only be used for child commands. + - When specified overrides the environment variable ECF_RID. Can only be used for task commands. * - :ref:`ssl_cli` - Enables the use of SSL when contacting the server. @@ -41,6 +47,9 @@ Options * - :ref:`user_cli` - Specifies the user name used to contact the server. Must be used in combination with option --password. + * - :ref:`version_cli` + - Show ecflow client version number, and version of the boost library used + .. toctree:: :maxdepth: 1 @@ -48,11 +57,14 @@ Options add (option) debug (option) + help (option) host (option) http (option) https (option) password (option) port (option) + remove (option) rid (option) ssl (option) user (option) + version (option) diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 4ab84cb6c..5df5a5614 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -71,7 +71,7 @@ std::string format_env_var(const nlohmann::json& var) { std::string make_client_env_description() { std::string help; - help += "The client considers, for both user and child commands, the following environment variables:\n\n"; + help += "The client considers, for both user and task commands, the following environment variables:\n\n"; for (const auto& var : ecf::HelpCatalog::manifest().at("environment_variables")) { if (var.at("applies_to").get() == "both") { @@ -88,7 +88,7 @@ std::string make_client_env_description() { std::string make_task_env_description() { std::string help; - help += "The following environment variables are used specifically by child commands:\n\n"; + help += "The following environment variables are used specifically by task commands:\n\n"; for (const auto& var : ecf::HelpCatalog::manifest().at("environment_variables")) { if (var.at("applies_to").get() == "task") { From 5e319d74846906e6010201bcc7e7ebd1760a1349 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 20:50:21 +0100 Subject: [PATCH 41/49] Avoid constexpr catalogue on NVidia Make the catalogue a runtime initialisation to avoid an apparent limitation of NVidia compiler, that otherwise fails to compile generated_client_help.hpp due to: > error type "const char [92920]" too large for constant-expression evaluation --- cmake/GenerateClientHelp.cmake | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmake/GenerateClientHelp.cmake b/cmake/GenerateClientHelp.cmake index 91ddb9244..2ff131bbc 100644 --- a/cmake/GenerateClientHelp.cmake +++ b/cmake/GenerateClientHelp.cmake @@ -58,7 +58,17 @@ file(WRITE "${OUTPUT}" "/* #include -inline constexpr std::string_view client_help_json = R\"ecflow_help( +/* + * Workaround for EDG-based compilers (e.g. NVidia) that complain about + * constexpr value exceeding the maximum allowed size. + */ +#if defined(__EDG__) +#define ECFLOW_HELP_CONSTEXPR const +#else +#define ECFLOW_HELP_CONSTEXPR constexpr +#endif + +inline ECFLOW_HELP_CONSTEXPR std::string_view client_help_json = R\"ecflow_help( ${manifest_content})ecflow_help\"; #endif /* ecflow_base_generated_client_help_HPP */ From 073e4867b461ada2bcf28ceaa73fa883046e4e88 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Thu, 23 Jul 2026 21:11:05 +0100 Subject: [PATCH 42/49] Address review findings in task-command help migration Gate the ECF_SSL environment-variable help on ECF_OPENSSL via a new env_var_enabled() predicate, so a client built without OpenSSL no longer advertises a variable it cannot use. This restores the pre-migration behaviour that was lost when the hardcoded env-var table moved into the help manifest. Add TestHelp.cpp covering the manifest-driven help rendering: the summary/task/user topic listings, the environment-variable banners for task and user commands, the option-versus-command distinction, the unknown-topic fallback, and ECF_SSL visibility per build. Document the new Help.cpp environment-variable helpers with Doxygen blocks, and neutralise HelpCatalog::not_provided so its text reads correctly when used as the fallback for commands as well as options. Rename the 'child command' glossary term to 'task command', matching the child-to-task rename already applied to the client help output. --- docs/glossary.rst | 77 ++++----- libs/base/src/ecflow/base/HelpCatalog.cpp | 2 +- libs/client/CMakeLists.txt | 1 + libs/client/src/ecflow/client/Help.cpp | 73 ++++++++- libs/client/test/TestHelp.cpp | 182 ++++++++++++++++++++++ 5 files changed, 291 insertions(+), 44 deletions(-) create mode 100644 libs/client/test/TestHelp.cpp diff --git a/docs/glossary.rst b/docs/glossary.rst index bc8c5b5a9..408e1de80 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -135,44 +135,7 @@ Glossary .. code-block:: shell ecflow_client --load= print check_only - - child command - Child (or Task) commands are called from within the :term:`ecf script` files. The table also includes the default action (from version 4.0.4) if the child command is part of a zombie. 'block' means the job will be held by the :term:`ecflow_client` command. Until time out, or manual/automatic intervention. - .. list-table:: - :header-rows: 1 - - * - Child (or Task) Command - - Description - - Zombie (default action) - * - :ref:`ecflow_client --init ` - - Sets the :term:`task` to the :term:`active` :term:`status` - - block - * - :ref:`ecflow_client --wait ` - - Wait for a expression to evaluate - - block - * - :ref:`ecflow_client --queue ` - - Update :term:`queue` step in server - - block - * - :ref:`ecflow_client --abort ` - - Sets the :term:`task` to the :term:`aborted` :term:`status` - - block - * - :ref:`ecflow_client --complete ` - - Sets the :term:`task` to the :term:`complete` :term:`status` - - block - * - :ref:`ecflow_client --event ` - - Set an :term:`event` - - fob - * - :ref:`ecflow_client --meter ` - - Change a :term:`meter` - - fob - * - :ref:`ecflow_client --label ` - - Change a :term:`label` - - fob - - The following environment variables must be set for the child commands. ECF_HOST, :term:`ECF_NAME` , :term:`ECF_PASS` and ECF_RID. See :term:`ecflow_client`. - - clock A clock is an attribute of a :term:`suite`. @@ -2003,7 +1966,45 @@ Glossary - :py:class:`ecflow.Task` * - :ref:`grammar` - :token:`task` - + + task command + Task commands (sometimes called Child commands) are executed within the :term:`ecf script` files. + The table also includes the default action (from version 4.0.4) if the task command is part of a zombie. + 'block' means the job will be held by the :term:`ecflow_client` command. Until time out, or manual/automatic intervention. + + .. list-table:: + :header-rows: 1 + + * - Task Command + - Description + - Zombie (default action) + * - :ref:`ecflow_client --init ` + - Sets the :term:`task` to the :term:`active` :term:`status` + - block + * - :ref:`ecflow_client --wait ` + - Wait for a expression to evaluate + - block + * - :ref:`ecflow_client --queue ` + - Update :term:`queue` step in server + - block + * - :ref:`ecflow_client --abort ` + - Sets the :term:`task` to the :term:`aborted` :term:`status` + - block + * - :ref:`ecflow_client --complete ` + - Sets the :term:`task` to the :term:`complete` :term:`status` + - block + * - :ref:`ecflow_client --event ` + - Set an :term:`event` + - fob + * - :ref:`ecflow_client --meter ` + - Change a :term:`meter` + - fob + * - :ref:`ecflow_client --label ` + - Change a :term:`label` + - fob + + The following environment variables must be set for the task commands. ECF_HOST, :term:`ECF_NAME` , :term:`ECF_PASS` and ECF_RID. See :term:`ecflow_client`. + time This defines a time dependency for a node. diff --git a/libs/base/src/ecflow/base/HelpCatalog.cpp b/libs/base/src/ecflow/base/HelpCatalog.cpp index 2330d7b98..e7157ef89 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.cpp +++ b/libs/base/src/ecflow/base/HelpCatalog.cpp @@ -14,7 +14,7 @@ namespace ecf { -const std::string HelpCatalog::not_provided = "Description not provided for this option"; +const std::string HelpCatalog::not_provided = "No description available"; const nlohmann::json& HelpCatalog::manifest() { static const nlohmann::json instance = nlohmann::json::parse(client_help_json); diff --git a/libs/client/CMakeLists.txt b/libs/client/CMakeLists.txt index 66a799a71..cbd801de4 100644 --- a/libs/client/CMakeLists.txt +++ b/libs/client/CMakeLists.txt @@ -54,6 +54,7 @@ set(test_srcs # Sources test/TestClient_main.cpp # test entry point test/TestClientOptions.cpp + test/TestHelp.cpp test/TestClientInterface.cpp test/TestClientConfigurations.cpp test/TestClientEnvironment.cpp diff --git a/libs/client/src/ecflow/client/Help.cpp b/libs/client/src/ecflow/client/Help.cpp index 5df5a5614..0c653352a 100644 --- a/libs/client/src/ecflow/client/Help.cpp +++ b/libs/client/src/ecflow/client/Help.cpp @@ -51,6 +51,19 @@ struct CommandFilter known_options{"add", "debug", "host", "password", "port", "rid", "ssl", "user", "http", "https"}; }; +/// +/// @brief Formats a single environment-variable manifest entry as two indented help lines. +/// +/// @details The first line carries the variable name, its type, and its requirement level; a +/// trailing asterisk marks a variable whose value can be overridden by a command-line option. The +/// second line carries the description. The layout matches the documentation renderer in +/// docs/client_api/build.py, so that the CLI help and the generated documentation agree. +/// +/// @param[in] var Manifest entry taken from the "environment_variables" array; must contain the +/// "required", "name", "type", and "description" fields, and may contain +/// "overridable_by". +/// @return The formatted two-line block, terminated by a newline. +/// std::string format_env_var(const nlohmann::json& var) { std::string required = var.at("required").get(); if (var.contains("overridable_by")) { @@ -69,12 +82,40 @@ std::string format_env_var(const nlohmann::json& var) { return line; } +/// +/// @brief Reports whether an environment variable applies to the current build. +/// +/// @details A variable may carry a "requires" field naming the build feature that gates it (for +/// example, ECF_SSL requires ECF_OPENSSL). A gated variable is advertised only when its feature is +/// compiled in, so that a client built without a feature does not describe variables that have no +/// effect. Variables with no "requires" field, or requiring a feature that is present, are enabled. +/// +/// @param[in] var Manifest entry taken from the "environment_variables" array. +/// @return true when the variable applies to the current build, false when a required feature is absent. +/// +bool env_var_enabled([[maybe_unused]] const nlohmann::json& var) { +#ifndef ECF_OPENSSL + if (var.contains("requires") && var.at("requires") == "ECF_OPENSSL") { + return false; + } +#endif + return true; +} + +/// +/// @brief Builds the environment-variable help common to both user and task commands. +/// +/// @details Collects every manifest entry whose "applies_to" field is "both" and appends a note +/// explaining the asterisk convention used for values that a command-line option can override. +/// +/// @return The assembled help text. +/// std::string make_client_env_description() { std::string help; help += "The client considers, for both user and task commands, the following environment variables:\n\n"; for (const auto& var : ecf::HelpCatalog::manifest().at("environment_variables")) { - if (var.at("applies_to").get() == "both") { + if (var.at("applies_to").get() == "both" && env_var_enabled(var)) { help += format_env_var(var); } } @@ -86,12 +127,20 @@ std::string make_client_env_description() { return help; } +/// +/// @brief Builds the environment-variable help specific to task commands. +/// +/// @details Collects every manifest entry whose "applies_to" field is "task" and appends a note +/// reminding that the mandatory variables are expected to be exported by the scripts. +/// +/// @return The assembled help text. +/// std::string make_task_env_description() { std::string help; help += "The following environment variables are used specifically by task commands:\n\n"; for (const auto& var : ecf::HelpCatalog::manifest().at("environment_variables")) { - if (var.at("applies_to").get() == "task") { + if (var.at("applies_to").get() == "task" && env_var_enabled(var)) { help += format_env_var(var); } } @@ -101,14 +150,28 @@ std::string make_task_env_description() { return help; } -// Lazily built and cached, matching HelpCatalog::manifest()'s own lazy parse: ecflow_client is -// invoked by a task potentially thousands of times over a suite run, and only a small fraction -// of those invocations ever request help, so this must not force a JSON parse on every one. +/// +/// @brief Returns the environment-variable help common to user and task commands. +/// +/// @details Built once on first use and cached, mirroring HelpCatalog::manifest()'s own lazy +/// parse: ecflow_client is invoked by a task potentially thousands of times over a suite run, and +/// only a small fraction of those invocations ever request help, so this must not force a JSON +/// parse on every one. +/// +/// @return Reference to the cached text, valid for the remaining lifetime of the process. +/// const std::string& client_env_description() { static const std::string instance = make_client_env_description(); return instance; } +/// +/// @brief Returns the environment-variable help specific to task commands. +/// +/// @details Built once on first use and cached, for the same reason as client_env_description(). +/// +/// @return Reference to the cached text, valid for the remaining lifetime of the process. +/// const std::string& client_task_env_description() { static const std::string instance = make_task_env_description(); return instance; diff --git a/libs/client/test/TestHelp.cpp b/libs/client/test/TestHelp.cpp new file mode 100644 index 000000000..0f3cb3e75 --- /dev/null +++ b/libs/client/test/TestHelp.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2009- ECMWF. + * + * This software is licensed under the terms of the Apache Licence version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include +#include + +#include +#include + +#include "ecflow/base/cts/CtsCmdRegistry.hpp" +#include "ecflow/client/Help.hpp" +#include "ecflow/test/scaffold/Naming.hpp" + +/// +/// @brief Tests the manifest-driven help rendering exposed by the Help class. +/// +/// @details The rendering helpers live in an anonymous namespace inside Help.cpp; they are +/// exercised here through the only public seam, streaming a Help built from the same +/// options_description the client assembles in production. +/// + +namespace { + +/// +/// @brief Builds the option description exactly as ClientOptions assembles it in production. +/// +/// @details Registers every command option through CtsCmdRegistry and then appends the global +/// command-line options, so that the rendered help matches what ecflow_client produces. +/// +/// @return The assembled option description. +/// +boost::program_options::options_description make_description() { + namespace po = boost::program_options; + + po::options_description desc("Client options"); + + CtsCmdRegistry registry; + registry.addAllOptions(desc); + + desc.add_options()("rid", po::value()->implicit_value(std::string{})); + desc.add_options()("port", po::value()->implicit_value(std::string{})); + desc.add_options()("host", po::value()->implicit_value(std::string{})); + desc.add_options()("user", po::value()->implicit_value(std::string{})); + desc.add_options()("password", po::value()->implicit_value(std::string{})); +#ifdef ECF_OPENSSL + desc.add_options()("ssl", ""); +#endif + desc.add_options()("http", ""); + desc.add_options()("https", ""); + + return desc; +} + +/// +/// @brief Renders the help output for the given topic. +/// +/// @details Mirrors `ecflow_client --help=` by streaming a Help built from the +/// production option description. +/// +/// @param[in] topic Help topic, such as "summary", "task", a command name, or an option name. +/// @return The rendered help text. +/// +std::string render(const std::string& topic) { + boost::program_options::options_description desc = make_description(); + std::ostringstream ss; + ss << Help{desc, topic}; + return ss.str(); +} + +/// +/// @brief Reports whether one string occurs within another. +/// +/// @param[in] haystack Text to search. +/// @param[in] needle Substring to look for. +/// @return true when @p needle occurs anywhere in @p haystack, false otherwise. +/// +bool contains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) != std::string::npos; +} + +// The banner sentences produced by make_client_env_description() and make_task_env_description(). +const std::string client_env_banner = "The client considers, for both user and task commands"; +const std::string task_env_banner = "The following environment variables are used specifically by task commands"; + +} // namespace + +BOOST_AUTO_TEST_SUITE(S_Client) + +BOOST_AUTO_TEST_SUITE(T_Help) + +BOOST_AUTO_TEST_CASE(test_summary_lists_task_and_user_commands) { + ECF_NAME_THIS_TEST(); + + std::string out = render("summary"); + BOOST_CHECK(contains(out, "Ecflow client commands:")); + // abort is a task command, alter a user command; both appear in the full summary. + BOOST_CHECK(contains(out, "abort")); + BOOST_CHECK(contains(out, "alter")); + // get_name_kind() labels the command kinds in the summary column. + BOOST_CHECK(contains(out, "task")); + BOOST_CHECK(contains(out, "user")); +} + +BOOST_AUTO_TEST_CASE(test_task_topic_lists_task_commands) { + ECF_NAME_THIS_TEST(); + + std::string out = render("task"); + BOOST_CHECK(contains(out, "Ecflow task client commands:")); + BOOST_CHECK(contains(out, "abort")); +} + +BOOST_AUTO_TEST_CASE(test_user_topic_lists_user_commands) { + ECF_NAME_THIS_TEST(); + + std::string out = render("user"); + BOOST_CHECK(contains(out, "Ecflow user client commands:")); + BOOST_CHECK(contains(out, "alter")); +} + +BOOST_AUTO_TEST_CASE(test_command_help_for_task_command_appends_both_env_banners) { + ECF_NAME_THIS_TEST(); + + std::string out = render("abort"); + // Heading plus the manifest description. + BOOST_CHECK(contains(out, "abort")); + // A task command gets both the common banner and the task-specific banner. + BOOST_CHECK(contains(out, client_env_banner)); + BOOST_CHECK(contains(out, "ECF_HOST")); + BOOST_CHECK(contains(out, task_env_banner)); + BOOST_CHECK(contains(out, "ECF_NAME")); +} + +BOOST_AUTO_TEST_CASE(test_command_help_for_user_command_omits_task_env_banner) { + ECF_NAME_THIS_TEST(); + + std::string out = render("alter"); + // A user command gets the common banner but not the task-specific one. + BOOST_CHECK(contains(out, client_env_banner)); + BOOST_CHECK(!contains(out, task_env_banner)); +} + +BOOST_AUTO_TEST_CASE(test_command_help_for_option_omits_env_banner) { + ECF_NAME_THIS_TEST(); + + std::string out = render("host"); + // An option is neither a user nor a task command, so no environment banner is appended. + BOOST_CHECK(contains(out, "host")); + BOOST_CHECK(!contains(out, client_env_banner)); + BOOST_CHECK(!contains(out, task_env_banner)); +} + +BOOST_AUTO_TEST_CASE(test_unknown_topic_falls_back_to_command_list) { + ECF_NAME_THIS_TEST(); + + // The renamed-away 'child' topic, and any other unknown name, degrade to the command list. + std::string out = render("child"); + BOOST_CHECK(contains(out, "No matching command found")); +} + +BOOST_AUTO_TEST_CASE(test_env_banner_ssl_visibility_follows_openssl_build) { + ECF_NAME_THIS_TEST(); + + // ECF_SSL carries requires: ECF_OPENSSL in the manifest, so it is advertised in the common + // environment-variable banner only when the client is built with OpenSSL. + std::string out = render("abort"); +#ifdef ECF_OPENSSL + BOOST_CHECK(contains(out, "ECF_SSL")); +#else + BOOST_CHECK(!contains(out, "ECF_SSL")); +#endif +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() From f542339dbe8735d1383a4b6510d6003c94c054e8 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 05:40:16 +0100 Subject: [PATCH 43/49] Complete child-to-task rename across the glossary A previous commit renamed the glossary term itself but left its references reading "child command". Make the glossary internally consistent with the client help output, without breaking the many :term:`child command` references in other documents. Convert every in-glossary :term:`child command` role and prose mention to "task command", and switch the applicability-table labels from (Child only)/(User + Child) to (Task only)/(User + Task). Add a "child command" glossary entry that redirects to "task command" ("See task command"), so cross-references from other pages still resolve. --- docs/glossary.rst | 113 ++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 408e1de80..2eb3d9d36 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -12,14 +12,14 @@ Glossary aborted Is a :term:`node` :term:`status`. - When the :term:`ECF_JOB_CMD` fails or the :term:`job file` sends a :term:`ecflow_client` --abort :term:`child command`, then + When the :term:`ECF_JOB_CMD` fails or the :term:`job file` sends a :term:`ecflow_client` --abort :term:`task command`, then the task is placed into a aborted state. active Is a :term:`node` :term:`status`. If :term:`job creation` was successful, and :term:`job file` has started, then the :term:`ecflow_client` --init - :term:`child command` is received by the :term:`ecflow_server` and the :term:`task` is placed into a active state + :term:`task command` is received by the :term:`ecflow_server` and the :term:`task` is placed into a active state autocancel autocancel is a way to automatically delete a :term:`node` which has completed. @@ -136,6 +136,9 @@ Glossary ecflow_client --load= print check_only + child command + See :term:`task command`. + clock A clock is an attribute of a :term:`suite`. @@ -194,7 +197,7 @@ Glossary The node can be set to complete: - By the :term:`complete expression` - - At job end when the :term:`task` receives the :ref:`ecflow_client –complete ` :term:`child command` + - At job end when the :term:`task` receives the :ref:`ecflow_client –complete ` :term:`task command` - Manually via the command line or GUI. When this happens any time attributes are expired in order. @@ -299,7 +302,7 @@ Glossary A :term:`task` that is dependent cannot be started as long as some dependency is holding it or any of its **parent** :term:`node` s. The :term:`ecflow_server` will check the dependencies every minute, during normal :term:`scheduling` **and** when any - :term:`child command` causes a state change in the :term:`suite definition`. + :term:`task command` causes a state change in the :term:`suite definition`. directives Directives appear in a ecf script. (i.e. typically .ecf file, but could be .py file).Directives start with a % character. This is referred to as :term:`ECF_MICRO` character. @@ -442,7 +445,7 @@ Glossary The ecFlow script is similar to a UNIX shell script. The differences, however, includes the addition of “C” like pre-processing :term:`directives` and ecFlow :term:`variable`\ s. - Also the script *must* include calls to the **init** and **complete** :term:`child command`\ s so that + Also the script *must* include calls to the **init** and **complete** :term:`task command`\ s so that the :term:`ecflow_server` is aware when the job starts (i.e changes state to :term:`active`) and finishes (i.e changes state to :term:`complete`) ECF_BASENAME @@ -502,7 +505,7 @@ Glossary .. important:: - This configuration is, by default, only applicable to :term:`child commands `. + This configuration is, by default, only applicable to :term:`task commands `. But the behaviour can be customised by setting the environment variable ECF_HOSTFILE_POLICY. ECF_INCLUDE @@ -662,7 +665,7 @@ Glossary The user must ensure that all the directories exists, including :term:`suite`/:term:`family`. If this is not done, you may well find task remains stuck in a submitted state. At ECMWF our submission scripts will ensure that directories exists. ECF_PASS - This is a generated :term:`variable`. During job generation process in the server, a unique password is generated and stored in the task. It then replaces %ECF_PASS% in the scripts(.ecf), with the actual value. When the job runs, ecflow_client reads this, as an environment variable, and passes it to the server. The server then compares this password with the one held on the task. This is used as a part of the authentication for child commands, and is used to detect zombies. + This is a generated :term:`variable`. During job generation process in the server, a unique password is generated and stored in the task. It then replaces %ECF_PASS% in the scripts(.ecf), with the actual value. When the job runs, ecflow_client reads this, as an environment variable, and passes it to the server. The server then compares this password with the one held on the task. This is used as a part of the authentication for task commands, and is used to detect zombies. The authentication process can be bypassed, and allow the job to proceed (i.e.. when the user is sure that there is only a single process, trying to communicate with the server), by adding it as a user variable. i.e.: @@ -739,11 +742,11 @@ Glossary ECF_TIMEOUT ECF_TIMEOUT is an environment variable, used by the :term:`ecflow_client`, and specifies how much time - (measured in seconds) a *child command* will continue to try contacting the server(s) before giving up. + (measured in seconds) a *task command* will continue to try contacting the server(s) before giving up. .. important:: - This timeout is only applicable to :term:`child commands `. + This timeout is only applicable to :term:`task commands `. When ECF_TIMEOUT is not set, the client uses the default value of 24 hours (24 * 60 * 60 seconds). The minimum value allowed is 60 seconds, while the maximum value is 24 hours. @@ -788,13 +791,13 @@ Glossary ECF_ZOMBIE_TIMEOUT ECF_ZOMBIE_TIMEOUT is an environment variable used by the :term:`ecflow_client`, and that specifies how much time - (measured in seconds) a *zombie* child command will continue to try contacting the server(s) before giving up. + (measured in seconds) a *zombie* task command will continue to try contacting the server(s) before giving up. .. important:: - This timeout is only applicable to :term:`child commands `. + This timeout is only applicable to :term:`task commands `. - A child command knows that the related :term:`task` has been deemed a :term:`zombie`, because the reply from + A task command knows that the related :term:`task` has been deemed a :term:`zombie`, because the reply from the server includes a *zombie* flag. When the client receives this flag, it will used ECF_ZOMBIE_TIMEOUT (instead of ECF_TIMEOUT). The ECF_ZOMBIE_TIMEOUT, in combination with the attempt to contact all hosts in ECF_HOSTFILE, allows a :term:`zombie` @@ -827,7 +830,7 @@ Glossary The following variables affect the execution of ecflow_client. - Since the :term:`ecf script` can call ecflow_client(i.e :term:`child command`) then typically + Since the :term:`ecf script` can call ``ecflow_client`` (i.e :term:`task command`) then typically some are set in an include header. .. list-table:: Environment variables used by *ecflow_client* @@ -839,7 +842,7 @@ Glossary * - ECF_HOST - (User + Child) + (User + Task) - The name of the :term:`ecflow_server` host | @@ -855,7 +858,7 @@ Glossary * - ECF_PORT - (User + Child) + (User + Task) - The port on the :term:`ecflow_server` host | @@ -871,7 +874,7 @@ Glossary * - NO_ECF - (User + Child) + (User + Task) - Speficies if client terminates immediately with success (to allow the scripts to be tested independently from the server) @@ -885,7 +888,7 @@ Glossary * - ECF_DENIED - (User + Child) + (User + Task) - Specifies if client terminates with error when the server denies contacts, in order to avoid waiting for ECF_TIMEOUT. @@ -900,7 +903,7 @@ Glossary * - ECF_SSL - (User + Child) + (User + Task) - Enables secure communication between server and client. | @@ -931,12 +934,12 @@ Glossary * - :term:`ECF_NAME` - (Child only) + (Task only) - The path to the task | - **This variable is mandatory for child commands** + **This variable is mandatory for task commands** | @@ -948,12 +951,12 @@ Glossary * - :term:`ECF_PASS` - (Child only) + (Task only) - The password of the task. | - **This variable is mandatory for child commands** + **This variable is mandatory for task commands** | @@ -961,12 +964,12 @@ Glossary * - ECF_RID - (Child only) + (Task only) - The remote id of the task. | - **This variable is mandatory for child commands** + **This variable is mandatory for task commands** | @@ -974,7 +977,7 @@ Glossary * - :term:`ECF_TRYNO` - (Child only) + (Task only) - The number of times the task has run. | @@ -983,7 +986,7 @@ Glossary * - ECF_HOSTFILE - (User + Child) + (User + Task) - The path to the file that lists alternate hosts to try, if connection to main host fails | @@ -994,9 +997,9 @@ Glossary * - ECF_HOSTFILE_POLICY - (User + Child) + (User + Task) - The policy, either "task" or "all", indicates when to perform retry based on the ECF_HOSTFILE. - The default policy is "task", meaning that the retry will only be performed for task (i.e. child) commands. + The default policy is "task", meaning that the retry will only be performed for task commands. If the policy is "all", the retry will be performed for both task and user commands (including :code:`ping`). | @@ -1011,12 +1014,12 @@ Glossary * - ECF_TIMEOUT - (Child only) + (Task only) - Maximum time (in seconds) for the client to perform operations (e.g. :code:`init`, :code:`abort`, :code:`complete`) with the server before giving up. | - This limit applies to all child commands, and user commands that have ECF_HOSTFILE_POLICY set to "all". When the client is unable to contact the server within the timeout period, it will exit with an error code. + This limit applies to all task commands, and user commands that have ECF_HOSTFILE_POLICY set to "all". When the client is unable to contact the server within the timeout period, it will exit with an error code. | @@ -1031,7 +1034,7 @@ Glossary * - ECF_CONNECT_TIMEOUT - (Child only) + (Task only) - Maximum time (in seconds) for the client to establish connection with the server before giving up. | @@ -1040,12 +1043,12 @@ Glossary * - ECF_ZOMBIE_TIMEOUT - (Child only) + (Task only) - Maximum time (in seconds) for the client to perform operations (e.g. :code:`init`, :code:`abort`, :code:`complete`) to get a reply from the server. | - This limit applies to child commands that have been marked as zombies by the server. When the client is unable to contact the server within the timeout period, it will exit with an error code. + This limit applies to task commands that have been marked as zombies by the server. When the client is unable to contact the server within the timeout period, it will exit with an error code. | @@ -1254,7 +1257,7 @@ Glossary There can be many events and they are displayed as nodes. - The event is updated by placing the ``--event`` :term:`child command` in a :term:`ecf script`. + The event is updated by placing the ``--event`` :term:`task command` in a :term:`ecf script`. An event has a number and possibly a name. If it is only defined as a number, its name is the text representation of the number without leading zeroes. @@ -1414,7 +1417,7 @@ Glossary The steps above transforms an :term:`ecf script` to a :term:`job file` that can be submitted by performing :term:`variable substitution` on the :term:`ECF_JOB_CMD` :term:`variable` and invoking the command. - The running jobs will communicate back to the :term:`ecflow_server` by calling :term:`child command`\ s. + The running jobs will communicate back to the :term:`ecflow_server` by calling :term:`task command`\ s. This causes :term:`status` changes on the :term:`node`\ s in the :term:`ecflow_server` and flags can be set to indicate various events. @@ -1442,7 +1445,7 @@ Glossary label A label has a name and a value and is a way of **displaying** information in :term:`ecflow_ui` - By placing a label :term:`child command`\ s in the :term:`ecf script` the user can be informed about progress + By placing a label :term:`task command`\ s in the :term:`ecf script` the user can be informed about progress in :term:`ecflow_ui`. Labels can be added to family nodes. To change the labels, scripts should use: @@ -1451,7 +1454,7 @@ Glossary ecflow_client --alter change label /path/to/family_node/with/label - If the label :term:`child command`\ s results in a :term:`zombie` then the default action if for the server to **fob**, this allows the ecflow_client command to exit normally. (i.e. without any errors). This default can be overridden by using a :term:`zombie` attribute. + If the label :term:`task command`\ s results in a :term:`zombie` then the default action if for the server to **fob**, this allows the ecflow_client command to exit normally. (i.e. without any errors). This default can be overridden by using a :term:`zombie` attribute. .. list-table:: @@ -1498,7 +1501,7 @@ Glossary suite late late -s +00:15 # report late for all task taking longer than 15 minutes in submitted state family familyName - late -c +02:00 # all child task that take longer than 2 hours to complete should raise a late flag + late -c +02:00 # all tasks that take longer than 2 hours to complete should raise a late flag task t1 # effective late -s +00:05 -c +02:00 late -s +00:05 @@ -1611,13 +1614,13 @@ Glossary The purpose of a meter is to signal proportional completion of a task and to be able to trigger another job which is waiting on this proportional completion. - The meter is updated by placing the --meter :term:`child command` in a :term:`ecf script`. Meters can be added to family nodes. To change the meters, in the scripts should use: + The meter is updated by placing the --meter :term:`task command` in a :term:`ecf script`. Meters can be added to family nodes. To change the meters, in the scripts should use: .. code-block:: shell ecflow_client --alter change meter /path/to/family_node/with/meter - If the meter :term:`child command` results in a zombie, then the default action if for the server to **fob**, this allows the ecflow_client command to exit normally (i.e. without any errors). This default can be overridden by using a zombie attribute. + If the meter :term:`task command` results in a zombie, then the default action if for the server to **fob**, this allows the ecflow_client command to exit normally (i.e. without any errors). This default can be overridden by using a zombie attribute. See also: @@ -1766,11 +1769,11 @@ Glossary endfamily endsuite - The :ref:`queue_cli` :term:`child command` will signal when a step is active, complete, or has aborted: + The :ref:`queue_cli` :term:`task command` will signal when a step is active, complete, or has aborted: .. code-block:: shell - # Note: because --queue is treated like a child command(init,complete,event,label,meter,abort,wait), the task path ECF_NAME is read from the environment + # Note: because --queue is treated like a task command(init,complete,event,label,meter,abort,wait), the task path ECF_NAME is read from the environment # The --queue command will search up the node hierarchy for the queue name. If not found it fails. @@ -2114,7 +2117,7 @@ Glossary A node with a trigger can only be activated when its trigger has expired. A trigger holds the node as long as the trigger expression evaluation returns false. - Trigger evaluation occurs when ever the :term:`child command` communicates with the server. i.e whenever + Trigger evaluation occurs when ever the :term:`task command` communicates with the server. i.e whenever there is a state change in the suite definition. The keywords in trigger expressions are: :term:`unknown`, :term:`suspended`, :term:`complete`, :term:`queued`, :term:`submitted`, :term:`active`, :term:`aborted` @@ -2214,7 +2217,7 @@ Glossary This is the default :term:`node` :term:`status` when a :term:`suite definition` is loaded into the :term:`ecflow_server` user command - User commands are any client to server requests that are **not** :term:`child command`\ s. + User commands are any client to server requests that are **not** :term:`task command`\ s. variable ecFlow makes heavy use of different kinds of variables.There are several kinds of variables: @@ -2289,22 +2292,22 @@ Glossary zombie Zombies are running jobs that fail authentication when communicating with the :term:`ecflow_server` - :term:`child command`\ s like (init, event,meter, label, abort,complete) are placed in the :term:`ecf script` + :term:`task command`\ s like (init, event,meter, label, abort,complete) are placed in the :term:`ecf script` file and are used to communicate with the :term:`ecflow_server`. - The :term:`ecflow_server` authenticates each connection attempt made by the :term:`child command`. + The :term:`ecflow_server` authenticates each connection attempt made by the :term:`task command`. Authentication can fail for a number of reasons: - - password(ECF_PASS) supplied with the :term:`child command`, does not match the one in the :term:`ecflow_server` - - path name(ECF_NAME) supplied with the :term:`child command`, does not locate a :term:`task` in the :term:`ecflow_server` - - process id(ECF_RID) supplied with :term:`child command`, does not correspond with the one stored in the :term:`ecflow_server` - - :term:`task` is already :term:`active`, but receives another init :term:`child command` - - :term:`task` is already :term:`complete`, but receives another :term:`child command` - - :term:`task` is already :term:`aborted`, but receives another :term:`child command` + - password(ECF_PASS) supplied with the :term:`task command`, does not match the one in the :term:`ecflow_server` + - path name(ECF_NAME) supplied with the :term:`task command`, does not locate a :term:`task` in the :term:`ecflow_server` + - process id(ECF_RID) supplied with :term:`task command`, does not correspond with the one stored in the :term:`ecflow_server` + - :term:`task` is already :term:`active`, but receives another init :term:`task command` + - :term:`task` is already :term:`complete`, but receives another :term:`task command` + - :term:`task` is already :term:`aborted`, but receives another :term:`task command` When authentication fails the job is considered to be a zombie. The :term:`ecflow_server` will keep a note of the zombie for a period of time, before it is automatically removed. - However the removed zombie, may well re-appear. (this is because each :term:`child command` will continue + However the removed zombie, may well re-appear. (this is because each :term:`task command` will continue attempting to contact the :term:`ecflow_server` for 24 hours. This is configurable see ECF_TIMEOUT on :term:`ecflow_client`) @@ -2323,7 +2326,7 @@ Glossary The zombie attribute defines how a :term:`zombie` should be handled in an automated fashion. Very careful consideration should be taken before this attribute is added as it may hide a genuine problem. It can be added to any :term:`node`. But is best defined at the :term:`suite` or :term:`family` level. - If there is no zombie attribute the default behaviour is to block the :term:`child command`. + If there is no zombie attribute the default behaviour is to block the :term:`task command`. To add a zombie attribute in python, please see: :py:class:`ecflow.ZombieAttr` @@ -2350,7 +2353,7 @@ Glossary * **ecf**: Jobs are created as part of the normal :term:`scheduling` - - Two init commands or task complete or aborted but receives another :term:`child command` + - Two init commands or task complete or aborted but receives another :term:`task command` - Server crashed (or terminated and restarted) and the recovered :term:`check point` file is out of date. - A :term:`task` is repeatedly re-run, earlier copies will not be remembered. - Job sent by another :term:`ecflow_server`, but which cannot talk to the original :term:`ecflow_server` From 422293ebc44600ce75f68a7edd4cb180c6d09636 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 06:18:24 +0100 Subject: [PATCH 44/49] Store help manifest descriptions one line per array element Each command/option "description" was an array of paragraphs joined by a blank line, with multi-line paragraphs held as escaped newlines in a single JSON string. Store one line per element instead (a blank line is an empty string), so no string carries an embedded newline and help-text edits diff line by line. Reconstruction joins the lines with a newline, an exact inverse, so the rendered help and generated docs are unchanged byte for byte. Both consumers now join with "\n" (HelpCatalog::description_for and build.py); the C++ join is made empty-line-safe. The schema renames description_block to description_line and drops its minimum length, and the validator now rejects an embedded newline in any line. Also silence -Woverlength-strings for the embedded manifest literal. --- cmake/CompilerOptions.cmake | 4 + docs/client_api/build.py | 9 +- docs/client_api/help.json | 1277 ++++++++++++++++++--- docs/client_api/help.schema.json | 9 +- docs/client_api/validate_help_manifest.py | 7 + libs/base/src/ecflow/base/HelpCatalog.cpp | 10 +- libs/base/src/ecflow/base/HelpCatalog.hpp | 7 +- libs/base/test/TestHelpCatalog.cpp | 26 + 8 files changed, 1155 insertions(+), 194 deletions(-) diff --git a/cmake/CompilerOptions.cmake b/cmake/CompilerOptions.cmake index a7ec218d2..8d890e8db 100644 --- a/cmake/CompilerOptions.cmake +++ b/cmake/CompilerOptions.cmake @@ -83,6 +83,7 @@ if (HAVE_WARNINGS) $<$,$,$,9.0.0>>:-Wno-deprecated-copy> # silence warnings in Qt5 related headers $<$,$>:-Wno-unused-result> $<$,$>:-Wno-unused-parameter> + $<$,$>:-Wno-overlength-strings> # silence warning for the embedded CLI help manifest string literal (generated_client_help.hpp) ## Clang (MacOS Homebrew, AMD Clang-base) $<$,$>:-Wno-deprecated-copy-with-user-provided-copy> # silence warnings in Qt5 related headers $<$,$>:-Wno-missing-field-initializers> # silence warning in Boost.Python related headers @@ -90,6 +91,7 @@ if (HAVE_WARNINGS) $<$,$,$,14.0.0>>:-Wno-c++20-attribute-extensions> # silence warning in Qt6 related headers $<$,$,$,21.0.0>>:-Wno-character-conversion> # silence warning in Qt6 related headers $<$,$,$,22.0.0>>:-Wno-c2y-extensions> # silence warning in Boost related headers (__COUNTER__) + $<$,$>:-Wno-overlength-strings> # silence warning for the embedded CLI help manifest string literal (generated_client_help.hpp) ## Clang (MacOS AppleClang) $<$,$>:-Wno-deprecated-copy-with-user-provided-copy> # silence warnings in Qt5 related headers $<$,$>:-Wno-missing-field-initializers> # silence warning in Boost.Python related headers @@ -97,10 +99,12 @@ if (HAVE_WARNINGS) $<$,$,$,14.0.0>>:-Wno-c++20-attribute-extensions> # silence warning in Qt6 related headers $<$,$,$,21.0.0>>:-Wno-character-conversion> # silence warning in Qt6 related headers $<$,$,$,22.0.0>>:-Wno-c2y-extensions> # silence warning in Boost related headers (__COUNTER__) + $<$,$>:-Wno-overlength-strings> # silence warning for the embedded CLI help manifest string literal (generated_client_help.hpp) ## Clang (Intel Clang-based) $<$,$>:-Wno-deprecated-copy-with-user-provided-copy> # silence warnings in Qt5 related headers $<$,$>:-Wno-missing-field-initializers> # silence warning in Boost.Python related headers $<$,$>:-Wno-unused-parameter> + $<$,$>:-Wno-overlength-strings> # silence warning for the embedded CLI help manifest string literal (generated_client_help.hpp) ) endif () diff --git a/docs/client_api/build.py b/docs/client_api/build.py index 3034189f5..7cafa9e99 100755 --- a/docs/client_api/build.py +++ b/docs/client_api/build.py @@ -166,10 +166,11 @@ def load_description_file(name): return f"" -def join_description(blocks): - # Reproduces HelpCatalog::description_for(): blocks are joined by a blank line, the same rule - # used to originally split the C++ source's paragraphs, including for pre-formatted content. - return "\n\n".join(blocks) +def join_description(lines): + # Reproduces HelpCatalog::description_for(): the description holds one line per element (a blank + # line is an empty string), joined by a newline to reconstruct the original text verbatim, + # including pre-formatted content. + return "\n".join(lines) def format_env_var(var): diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 31611fa7c..35ac01a89 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -15,9 +15,17 @@ "implementation": "AbortCmd", "summary": "Mark task as aborted. For use in the '.ecf' script file *only*", "description": [ - "Mark task as aborted. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1 = (optional) string(reason)\n Optionally provide a reason why the abort was raised", - "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.", - "Usage:\n ecflow_client --abort=reasonX" + "Mark task as aborted. For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables", + " arg1 = (optional) string(reason)", + " Optionally provide a reason why the abort was raised", + "", + "If this task command is a zombie, then the default action will be to *block*.", + "The default can be overridden by using zombie attributes.", + "Otherwise the blocking period is defined by ECF_TIMEOUT.", + "", + "Usage:", + " ecflow_client --abort=reasonX" ], "arguments": [ { @@ -37,42 +45,109 @@ "summary": "Alter the node according to the options.", "description": [ "Alter the node according to the options.", + "", "arg1 = [ delete | change | add | set_flag | clear_flag | sort ]", - "arg2 = For delete:\n [ variable | time | today | date | day | cron | event | meter | late | generic |\n queue | label | trigger | complete | repeat | limit | inlimit | limit_path |\n zombie | aviso | mirror ]", - " For change:\n [ variable | clock_type | clock_gain | clock_date | clock_sync | event | meter |\n label | trigger | complete | repeat | limit_max | limit_value | defstatus |\n late | time | today | aviso | mirror ]", - " For add:\n [ variable | time | today | date | day | zombie | event | meter | late | limit |\n inlimit | label | aviso | mirror ]", - " For set_flag or clear_flag:\n [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed |\n statuscmd_failed | killcmd_failed | no_script | killed | status | late |\n message complete | queue_limit | task_waiting | locked | zombie | archived |\n restored | threshold | log_error | checkpt_error ]", - " For sort:\n [ event | meter | label | variable| limit | all ]", + "", + "arg2 = For delete:", + " [ variable | time | today | date | day | cron | event | meter | late | generic |", + " queue | label | trigger | complete | repeat | limit | inlimit | limit_path |", + " zombie | aviso | mirror ]", + "", + " For change:", + " [ variable | clock_type | clock_gain | clock_date | clock_sync | event | meter |", + " label | trigger | complete | repeat | limit_max | limit_value | defstatus |", + " late | time | today | aviso | mirror ]", + "", + " For add:", + " [ variable | time | today | date | day | zombie | event | meter | late | limit |", + " inlimit | label | aviso | mirror ]", + "", + " For set_flag or clear_flag:", + " [ force_aborted | user_edit | task_aborted | edit_failed | ecfcmd_failed |", + " statuscmd_failed | killcmd_failed | no_script | killed | status | late |", + " message complete | queue_limit | task_waiting | locked | zombie | archived |", + " restored | threshold | log_error | checkpt_error ]", + "", + " For sort:", + " [ event | meter | label | variable| limit | all ]", + "", "arg3 = [ | ]", + "", "arg4 = ", + "", "arg5 = ( (...)) - at least one node path required.", + "", "*Important Notes*", + "", " * All paths must start with a leading '/' character.", + "", " * To update, create or remove server variables use '/' for path.", + "", " * When updating unnamed attributes (Repeat, Trigger, Complete, ...) the name/arg3 is not necessary.", + "", " * After changing the clock the suite needs to be re-queued for the change to take effect.", - " * When adding or updating node attributes (e.g. variable, meter, event, label, limits, late)\n the name (arg3) and value (arg4) must be quoted.", + "", + " * When adding or updating node attributes (e.g. variable, meter, event, label, limits, late)", + " the name (arg3) and value (arg4) must be quoted.", + "", " * When sorting attributes, 'recursive' can be used as the value (arg3).", - " * When adding a meter, the value (arg4) is expected to be a comma-separated triplet\n of numerical values the form \",,\" (n.b. no spaces are allowed).", + "", + " * When adding a meter, the value (arg4) is expected to be a comma-separated triplet", + " of numerical values the form \",,\" (n.b. no spaces are allowed).", + "", " * When adding an event, the non-optional value (arg4) must be either \"set\" or \"clear\".", - " * When adding or updating aviso and mirror attributes, the value (arg4) is expected to be\n a quoted list of configuration options. For example:\n * for aviso, \"--remote_path /s1/f1/t2 --remote_host host --polling 20 --remote_port 3141 --ssl)\"\n * for mirror, \"--listener '{ \\\"event\\\": \\\"mars\\\", \\\"request\\\": { \\\"class\\\": \"od\" } }'\n --url http://aviso/ --schema /path/to/schema --polling 60\"", - " * For both aviso and mirror, the special value \"reload\" forces reloading the configuration.\n This is typically useful after updating variables used to configure these kind of attributes.", + "", + " * When adding or updating aviso and mirror attributes, the value (arg4) is expected to be", + " a quoted list of configuration options. For example:", + " * for aviso, \"--remote_path /s1/f1/t2 --remote_host host --polling 20 --remote_port 3141 --ssl)\"", + " * for mirror, \"--listener '{ \\\"event\\\": \\\"mars\\\", \\\"request\\\": { \\\"class\\\": \"od\" } }'", + " --url http://aviso/ --schema /path/to/schema --polling 60\"", + "", + " * For both aviso and mirror, the special value \"reload\" forces reloading the configuration.", + " This is typically useful after updating variables used to configure these kind of attributes.", + "", "Usage:", - " ecflow_client --alter=add variable \"value\" / # add server variable\n ecflow_client --alter=add variable \"value\" /path/to/node # add node variable", + "", + " ecflow_client --alter=add variable \"value\" / # add server variable", + " ecflow_client --alter=add variable \"value\" /path/to/node # add node variable", + "", " ecflow_client --alter=add time \"+00:20\" /path/to/node", + "", " ecflow_client --alter=add date \"01.*.*\" /path/to/node", + "", " ecflow_client --alter=add day \"sunday\" /path/to/node", + "", " ecflow_client --alter=add label \"label_value\" /path/to/node", + "", " ecflow_client --alter=add event \"set\"|\"clear\" /path/to/node", + "", " ecflow_client --alter=add meter \",,value\" /path/to/node", + "", " ecflow_client --alter=add late \"-s 00:01 -a 14:30 -c +00:01\" /path/to/node", + "", " ecflow_client --alter=add limit mars \"100\" /path/to/node", + "", " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"10\" /path/to/node", + "", " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-s 10\" /path/to/node", + "", " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-n 10\" /path/to/node", - " # zombie attributes have the following structure:\n `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time`\n zombie_type = \"user\" | \"ecf\" | \"path\" | \"ecf_pid\" | \"ecf_passwd\" | \"ecf_pid_passwd\"\n client_side_action = \"fob\" | \"fail\" | \"block\"\n server_side_action = \"adopt\" | \"delete\" | \"kill\"\n child = \"init\" | \"event\" | \"meter\" | \"label\" | \"wait\" | \"abort\" | \"complete\" | \"queue\"\n zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60", - " ecflow_client --alter=add zombie \"ecf:fail::\" /path/to/node # ask system zombies to fail\n ecflow_client --alter=add zombie \"user:fail::\" /path/to/node # ask user generated zombies to fail\n ecflow_client --alter=add zombie \"path:fail::\" /path/to/node # ask path zombies to fail", - " ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED\n ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode\n" + "", + " # zombie attributes have the following structure:", + " `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time`", + " zombie_type = \"user\" | \"ecf\" | \"path\" | \"ecf_pid\" | \"ecf_passwd\" | \"ecf_pid_passwd\"", + " client_side_action = \"fob\" | \"fail\" | \"block\"", + " server_side_action = \"adopt\" | \"delete\" | \"kill\"", + " child = \"init\" | \"event\" | \"meter\" | \"label\" | \"wait\" | \"abort\" | \"complete\" | \"queue\"", + " zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60", + "", + " ecflow_client --alter=add zombie \"ecf:fail::\" /path/to/node # ask system zombies to fail", + " ecflow_client --alter=add zombie \"user:fail::\" /path/to/node # ask user generated zombies to fail", + " ecflow_client --alter=add zombie \"path:fail::\" /path/to/node # ask path zombies to fail", + "", + " ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED", + " ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode", + "" ] }, { @@ -82,10 +157,42 @@ "implementation": "PathsCmd", "summary": "Archives suite or family nodes *IF* they have child nodes(otherwise does nothing).", "description": [ - "Archives suite or family nodes *IF* they have child nodes(otherwise does nothing).\nSaves the suite/family nodes to disk, and then removes the child nodes from the definition.\nThis saves memory in the server, when dealing with huge definitions that are not needed.\nIt improves time taken to checkpoint and reduces network bandwidth.\nIf the node is re-queued or begun, the child nodes are automatically restored.\nUse --restore to reload the archived nodes manually\nCare must be taken if you have trigger reference to the archived nodes\nThe nodes are saved to the file ECF_HOME/...check,\nwhere '/' has been replaced with ':' in ECF_NAME", - "Nodes like (family and suites) can also to automatically archived by using,\nthe 'autoarchive' attribute. The attribute is only applied once the node is complete", - "suite autoarchive\n family f1\n autoarchive +01:00 # archive one hour after complete\n task t1\n endfamily\n family f2\n autoarchive 01:00 # archive at 1 am in morning after complete\n task t1\n endfamily\n family f3\n autoarchive 10 # archive 10 days after complete\n task t1\n endfamily\n family f4\n autoarchive 0 # archive immediately (upto 60s) after complete\n task t1\n endfamily\nendsuite", - "Usage::\n --archive=/s1 # archive suite s1\n --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2\n --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" + "Archives suite or family nodes *IF* they have child nodes(otherwise does nothing).", + "Saves the suite/family nodes to disk, and then removes the child nodes from the definition.", + "This saves memory in the server, when dealing with huge definitions that are not needed.", + "It improves time taken to checkpoint and reduces network bandwidth.", + "If the node is re-queued or begun, the child nodes are automatically restored.", + "Use --restore to reload the archived nodes manually", + "Care must be taken if you have trigger reference to the archived nodes", + "The nodes are saved to the file ECF_HOME/...check,", + "where '/' has been replaced with ':' in ECF_NAME", + "", + "Nodes like (family and suites) can also to automatically archived by using,", + "the 'autoarchive' attribute. The attribute is only applied once the node is complete", + "", + "suite autoarchive", + " family f1", + " autoarchive +01:00 # archive one hour after complete", + " task t1", + " endfamily", + " family f2", + " autoarchive 01:00 # archive at 1 am in morning after complete", + " task t1", + " endfamily", + " family f3", + " autoarchive 10 # archive 10 days after complete", + " task t1", + " endfamily", + " family f4", + " autoarchive 0 # archive immediately (upto 60s) after complete", + " task t1", + " endfamily", + "endsuite", + "", + "Usage::", + " --archive=/s1 # archive suite s1", + " --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2", + " --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" ] }, { @@ -95,7 +202,18 @@ "implementation": "BeginCmd", "summary": "Begin playing the definition in the server.", "description": [ - "Begin playing the definition in the server.\nExpects zero or a single quoted string.\n arg1 = suite-name | Nothing | force\n play the chosen suite, if no arg specified, play all suites, in the definition\n force means reset the begin status on the suites and bypass checks.\n This is only required if suite-name is provide as the first argument\n Using force can cause the creation of zombies\nUsage:\n--begin # will begin all suites\n--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted\n--begin=\"mySuite\" # begin playing suite of name 'mySuite'\n--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check" + "Begin playing the definition in the server.", + "Expects zero or a single quoted string.", + " arg1 = suite-name | Nothing | force", + " play the chosen suite, if no arg specified, play all suites, in the definition", + " force means reset the begin status on the suites and bypass checks.", + " This is only required if suite-name is provide as the first argument", + " Using force can cause the creation of zombies", + "Usage:", + "--begin # will begin all suites", + "--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted", + "--begin=\"mySuite\" # begin playing suite of name 'mySuite'", + "--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check" ] }, { @@ -105,7 +223,14 @@ "implementation": "ClientHandleCmd", "summary": "Add a set of suites, to an existing handle.", "description": [ - "Add a set of suites, to an existing handle.\n arg1 = handle(integer) # The handle must be an integer that is > 0\n arg2 = names # should be a list of suite names, names not in the definition are ignored\nUsage:\n --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10\nAn error is returned if the handle had not previously been registered\nThe handle is created with --ch_register command\nTo list all suites and handles use --ch_suites" + "Add a set of suites, to an existing handle.", + " arg1 = handle(integer) # The handle must be an integer that is > 0", + " arg2 = names # should be a list of suite names, names not in the definition are ignored", + "Usage:", + " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10", + "An error is returned if the handle had not previously been registered", + "The handle is created with --ch_register command", + "To list all suites and handles use --ch_suites" ] }, { @@ -115,7 +240,14 @@ "implementation": "ClientHandleCmd", "summary": "Change an existing handle so that new suites can be added automatically.", "description": [ - "Change an existing handle so that new suites can be added automatically.\n arg1 = handle(integer) # The handle must be an integer that is > 0\n arg2 = true | false # true means add new suites to my list, when they are created\nUsage:\n --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it\n --ch_auto_add=10 false # modify handle 10 so that no new suites are added\nThe handle is created with --ch_register command\nTo list all suites and handles use --ch_suites" + "Change an existing handle so that new suites can be added automatically.", + " arg1 = handle(integer) # The handle must be an integer that is > 0", + " arg2 = true | false # true means add new suites to my list, when they are created", + "Usage:", + " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it", + " --ch_auto_add=10 false # modify handle 10 so that no new suites are added", + "The handle is created with --ch_register command", + "To list all suites and handles use --ch_suites" ] }, { @@ -125,7 +257,14 @@ "implementation": "ClientHandleCmd", "summary": "Drop/de-register the client handle.", "description": [ - "Drop/de-register the client handle.\nUn-used handle should be dropped otherwise they will stay, in the server.\n arg1 = handle(integer) # The handle must be an integer that is > 0\nUsage:\n --ch_drop=10 # drop the client handle 10\nAn error is returned if the handle had not previously been registered\nThe handle stored on the local client is set to zero\nTo list all suites and handles use --ch_suites" + "Drop/de-register the client handle.", + "Un-used handle should be dropped otherwise they will stay, in the server.", + " arg1 = handle(integer) # The handle must be an integer that is > 0", + "Usage:", + " --ch_drop=10 # drop the client handle 10", + "An error is returned if the handle had not previously been registered", + "The handle stored on the local client is set to zero", + "To list all suites and handles use --ch_suites" ] }, { @@ -135,7 +274,15 @@ "implementation": "ClientHandleCmd", "summary": "Drop/de-register all handles associated with the given user.", "description": [ - "Drop/de-register all handles associated with the given user.\nIf no user provided will drop for current user. Client must ensure un-used handle are dropped\notherwise they will stay, in the server.\n arg1 = user # The user to be drooped, if left empty drop current user \nUsage:\n --ch_drop_user=ma0 # drop all handles associated with user ma0\n --ch_drop_user # drop all handles associated with current user\nAn error is returned if no registered handles\nTo list all suites and handles use --ch_suites" + "Drop/de-register all handles associated with the given user.", + "If no user provided will drop for current user. Client must ensure un-used handle are dropped", + "otherwise they will stay, in the server.", + " arg1 = user # The user to be drooped, if left empty drop current user ", + "Usage:", + " --ch_drop_user=ma0 # drop all handles associated with user ma0", + " --ch_drop_user # drop all handles associated with current user", + "An error is returned if no registered handles", + "To list all suites and handles use --ch_suites" ] }, { @@ -145,7 +292,23 @@ "implementation": "ClientHandleCmd", "summary": "Register interest in a set of suites.", "description": [ - "Register interest in a set of suites.\nIf a definition has lots of suites, but the client. is only interested in a small subset,\nThen using this command can reduce network bandwidth and synchronisation will be quicker.\nThis command will create a client handle, which must be used for any other changes.\nThe newly created handle can be shown with the --ch_suites command\nDeleted suites will stay registered, and must be explicitly removed/dropped.\nNote: Suites can be registered before they are loaded into the server\nThis command affects news() and sync() commands\n arg1 = true | false # true means add new suites to my list, when they are created\n arg2 = names # should be a list of suite names, names not in the definition are ignored\nUsage:\n --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites\n --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only\n --ch_register=false # register handle, suites will be added later on\n --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites\n # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first\nTo list all suites and handles use --ch_suites" + "Register interest in a set of suites.", + "If a definition has lots of suites, but the client. is only interested in a small subset,", + "Then using this command can reduce network bandwidth and synchronisation will be quicker.", + "This command will create a client handle, which must be used for any other changes.", + "The newly created handle can be shown with the --ch_suites command", + "Deleted suites will stay registered, and must be explicitly removed/dropped.", + "Note: Suites can be registered before they are loaded into the server", + "This command affects news() and sync() commands", + " arg1 = true | false # true means add new suites to my list, when they are created", + " arg2 = names # should be a list of suite names, names not in the definition are ignored", + "Usage:", + " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites", + " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only", + " --ch_register=false # register handle, suites will be added later on", + " --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites", + " # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first", + "To list all suites and handles use --ch_suites" ] }, { @@ -155,7 +318,13 @@ "implementation": "ClientHandleCmd", "summary": "Remove a set of suites, from an existing handle.", "description": [ - "Remove a set of suites, from an existing handle.\n arg1 = handle(integer) # The handle must be an integer that is > 0\n arg2 = names # should be a list of suite names, names not in the definition are ignored\nUsage:\n --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10\nThe handle is created with --ch_register command\nTo list all suites and handles use --ch_suites" + "Remove a set of suites, from an existing handle.", + " arg1 = handle(integer) # The handle must be an integer that is > 0", + " arg2 = names # should be a list of suite names, names not in the definition are ignored", + "Usage:", + " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10", + "The handle is created with --ch_register command", + "To list all suites and handles use --ch_suites" ] }, { @@ -173,7 +342,15 @@ "implementation": "PathsCmd", "summary": "Checks the expression and limits in the server. Will also check trigger references.", "description": [ - "Checks the expression and limits in the server. Will also check trigger references.\nTrigger expressions that reference paths that don't exist, will be reported as errors.\n(Note: On the client side unresolved paths in trigger expressions must\nhave an associated 'extern' specified)\n arg = [ _all_ | / | list of node paths ]\nUsage:\n --check=_all_ # Checks all the suites\n --check=/ # Checks all the suites\n --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" + "Checks the expression and limits in the server. Will also check trigger references.", + "Trigger expressions that reference paths that don't exist, will be reported as errors.", + "(Note: On the client side unresolved paths in trigger expressions must", + "have an associated 'extern' specified)", + " arg = [ _all_ | / | list of node paths ]", + "Usage:", + " --check=_all_ # Checks all the suites", + " --check=/ # Checks all the suites", + " --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" ] }, { @@ -183,7 +360,11 @@ "implementation": "CtsNodeCmd", "summary": "Test hierarchical Job generation only, for chosen Node.", "description": [ - "Test hierarchical Job generation only, for chosen Node.\nThe jobs are generated independent of the dependencies\nThis will generate the jobs *only*, i.e. no job submission. Used for checking job generation only\n arg = node path | arg = NULL\n If no node path specified generates for all Tasks in the definition. For Test only" + "Test hierarchical Job generation only, for chosen Node.", + "The jobs are generated independent of the dependencies", + "This will generate the jobs *only*, i.e. no job submission. Used for checking job generation only", + " arg = node path | arg = NULL", + " If no node path specified generates for all Tasks in the definition. For Test only" ] }, { @@ -193,7 +374,38 @@ "implementation": "CheckPtCmd", "summary": "Forces the definition file in the server to be written to disk *or* allow mode,", "description": [ - "Forces the definition file in the server to be written to disk *or* allow mode,\ninterval and alarm to be changed.\nWhenever the check pt file is written to disk, it is measured.\nIf the time to save to disk is greater than the default of 30 seconds,\nthen an alarm is raised. This can be seen in the GUI as a late flag on the server.\nOnce the late flag has been set it will need to manually cleared in the GUI\nor by using --alter functionality\nNote excessive save times can interfere with job scheduling.\nThe alarm threshold can be changed. See below.\n arg1 = (optional) mode [ never | on_time | on_time: | always | ]\n never : Never check point the definition in the server\n on_time : Turn on automatic check pointing at interval stored on server\n on_time : Turn on automatic check point, with the specified interval in seconds\n alarm : Modify the alarm notification time for check pt saving to disk\n always : Check point at any change in node tree, *NOT* recommended for large definitions\n : This specifies the interval in seconds when server should automatically check pt.\n This will only take effect of mode is on_time/CHECK_ON_TIME\n Should ideally be a value greater than 60 seconds, default is 120 seconds\nUsage:\n --check_pt\n Immediately check point the definition held in the server\n --check_pt=never\n Switch off check pointing\n --check_pt=on_time\n Start automatic check pointing at the interval stored in the server\n --check_pt=180\n Change the check pt interval to 180 seconds\n --check_pt=on_time:90\n Change mode and interval, to automatic check pointing every 90 seconds\n --check_pt=alarm:35\n Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds\n set the late flag on the server." + "Forces the definition file in the server to be written to disk *or* allow mode,", + "interval and alarm to be changed.", + "Whenever the check pt file is written to disk, it is measured.", + "If the time to save to disk is greater than the default of 30 seconds,", + "then an alarm is raised. This can be seen in the GUI as a late flag on the server.", + "Once the late flag has been set it will need to manually cleared in the GUI", + "or by using --alter functionality", + "Note excessive save times can interfere with job scheduling.", + "The alarm threshold can be changed. See below.", + " arg1 = (optional) mode [ never | on_time | on_time: | always | ]", + " never : Never check point the definition in the server", + " on_time : Turn on automatic check pointing at interval stored on server", + " on_time : Turn on automatic check point, with the specified interval in seconds", + " alarm : Modify the alarm notification time for check pt saving to disk", + " always : Check point at any change in node tree, *NOT* recommended for large definitions", + " : This specifies the interval in seconds when server should automatically check pt.", + " This will only take effect of mode is on_time/CHECK_ON_TIME", + " Should ideally be a value greater than 60 seconds, default is 120 seconds", + "Usage:", + " --check_pt", + " Immediately check point the definition held in the server", + " --check_pt=never", + " Switch off check pointing", + " --check_pt=on_time", + " Start automatic check pointing at the interval stored in the server", + " --check_pt=180", + " Change the check pt interval to 180 seconds", + " --check_pt=on_time:90", + " Change mode and interval, to automatic check pointing every 90 seconds", + " --check_pt=alarm:35", + " Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds", + " set the late flag on the server." ] }, { @@ -203,9 +415,19 @@ "implementation": "CompleteCmd", "summary": "Mark task as complete. For use in the '.ecf' script file *only*", "description": [ - "Mark task as complete. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables", - "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.\nThe init command allows variables to be added, and complete command\nallows for them to be removed.\n arg1(--remove)(optional) = a list of variables to removed from this task", - "Usage:\n ecflow_client --complete\n ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" + "Mark task as complete. For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables", + "", + "If this task command is a zombie, then the default action will be to *block*.", + "The default can be overridden by using zombie attributes.", + "Otherwise the blocking period is defined by ECF_TIMEOUT.", + "The init command allows variables to be added, and complete command", + "allows for them to be removed.", + " arg1(--remove)(optional) = a list of variables to removed from this task", + "", + "Usage:", + " ecflow_client --complete", + " ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ], "arguments": [ { @@ -242,7 +464,16 @@ "implementation": "DeleteCmd", "summary": "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.", "description": [ - "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.\n arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted tasks\n arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt\n arg3 = node paths | _all_ # _all_ means delete all suites\n # node paths must start with a leading '/'\nUsage:\n --delete=_all_ # Delete all suites in server. Use with care.\n --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt\n --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted\n --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt" + "Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server.", + " arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted tasks", + " arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt", + " arg3 = node paths | _all_ # _all_ means delete all suites", + " # node paths must start with a leading '/'", + "Usage:", + " --delete=_all_ # Delete all suites in server. Use with care.", + " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt", + " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted", + " --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt" ] }, { @@ -252,7 +483,12 @@ "implementation": "PathsCmd", "summary": "Returns the edit history associated with a Node.", "description": [ - "Returns the edit history associated with a Node.\nCan also be used to clear the edit history.\nUsage::\n --edit_history=/s1/f1/t1 # return history of changes for the given node\n --edit_history=clear # clear/purge *ALL* edit history from all nodes.\n" + "Returns the edit history associated with a Node.", + "Can also be used to clear the edit history.", + "Usage::", + " --edit_history=/s1/f1/t1 # return history of changes for the given node", + " --edit_history=clear # clear/purge *ALL* edit history from all nodes.", + "" ] }, { @@ -262,12 +498,55 @@ "implementation": "EditScriptCmd", "summary": "Allows user to edit, pre-process and submit the script.", "description": [ - "Allows user to edit, pre-process and submit the script.\nWill allow pre-processing of arbitrary file with 'pre_process_file' option\n arg1 = path to task # The path to the task/alias\n arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ]\n edit : will return the script file to standard out. The script will\n include used variables enclosed between %comment/%end at the\n start of the file\n pre_process: Will return the script file to standard out.The script will\n include used variables enclosed between %comment/%end at the\n start of the file and with all %include expanded\n submit: Will extract the used variables from the supplied file, i.e\n between the %comment/%end and use these them to generate the\n job using the ecf file accessible from the server\n pre_process_file: Will pre process the user supplied file.\n Will expand includes,variable substitution,\n remove manual & comment sections.\n submit_file: Like submit, but the supplied file, is submitted by the server\n The last 2 options allow complete freedom to debug the script file\n arg3 = [ path_to_script_file ]\n needed for option [ pre_process_file | submit_file ]\n arg4 = create_alias (optional) default value is false, for use with 'submit_file' option\n arg5 = no_run (optional) default value is false, i.e immediately run the alias\n is no_run is specified the alias in only created\nUsage:\n--edit_script=/path/to/task edit > script_file\n server returns script with the used variables to standard out\n The user can choose to edit this file", - "--edit_script=/path/to/task pre_process > pre_processed_script_file\n server will pre process the ecf file accessible from the server\n (i.e expand all %includes) and return the file to standard out", - "--edit_script=/path/to/task submit script_file\n Will extract the used variables in the 'script_file' and will uses these\n variables during variable substitution of the ecf file accessible by the\n server. This is then submitted as a job", - "--edit_script=/path/to/task pre_process_file file_to_pre_process\n The server will pre-process the user supplied file and return the contents\n to standard out. This pre-processing is the same as job file processing,\n but on a arbitrary file", - "--edit_script=/path/to/task submit_file file_to_submit\n Will extract the used variables in the 'file_to_submit' and will uses these\n variables during variable substitution, the file is then submitted for job\n generation by the server", - "--edit_script=/path/to/task submit_file file_to_submit create_alias\n Like the the previous example but will create and run as an alias" + "Allows user to edit, pre-process and submit the script.", + "Will allow pre-processing of arbitrary file with 'pre_process_file' option", + " arg1 = path to task # The path to the task/alias", + " arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ]", + " edit : will return the script file to standard out. The script will", + " include used variables enclosed between %comment/%end at the", + " start of the file", + " pre_process: Will return the script file to standard out.The script will", + " include used variables enclosed between %comment/%end at the", + " start of the file and with all %include expanded", + " submit: Will extract the used variables from the supplied file, i.e", + " between the %comment/%end and use these them to generate the", + " job using the ecf file accessible from the server", + " pre_process_file: Will pre process the user supplied file.", + " Will expand includes,variable substitution,", + " remove manual & comment sections.", + " submit_file: Like submit, but the supplied file, is submitted by the server", + " The last 2 options allow complete freedom to debug the script file", + " arg3 = [ path_to_script_file ]", + " needed for option [ pre_process_file | submit_file ]", + " arg4 = create_alias (optional) default value is false, for use with 'submit_file' option", + " arg5 = no_run (optional) default value is false, i.e immediately run the alias", + " is no_run is specified the alias in only created", + "Usage:", + "--edit_script=/path/to/task edit > script_file", + " server returns script with the used variables to standard out", + " The user can choose to edit this file", + "", + "--edit_script=/path/to/task pre_process > pre_processed_script_file", + " server will pre process the ecf file accessible from the server", + " (i.e expand all %includes) and return the file to standard out", + "", + "--edit_script=/path/to/task submit script_file", + " Will extract the used variables in the 'script_file' and will uses these", + " variables during variable substitution of the ecf file accessible by the", + " server. This is then submitted as a job", + "", + "--edit_script=/path/to/task pre_process_file file_to_pre_process", + " The server will pre-process the user supplied file and return the contents", + " to standard out. This pre-processing is the same as job file processing,", + " but on a arbitrary file", + "", + "--edit_script=/path/to/task submit_file file_to_submit", + " Will extract the used variables in the 'file_to_submit' and will uses these", + " variables during variable substitution, the file is then submitted for job", + " generation by the server", + "", + "--edit_script=/path/to/task submit_file file_to_submit create_alias", + " Like the the previous example but will create and run as an alias" ] }, { @@ -277,10 +556,21 @@ "implementation": "EventCmd", "summary": "Change event. For use in the '.ecf' script file *only*", "description": [ - "Change event. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string | int) = event-name", + "Change event. For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables", + " arg1(string | int) = event-name", + "", " arg2(string)(optional) = [ set | clear] default value is set", - "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", - "Usage:\n ecflow_client --event=ev # set the event, default since event initial value is clear\n ecflow_client --event=ev set # set the event, explicit\n ecflow_client --event=ev clear # clear the event, use when event initial value is set\n" + "", + "If this task command is a zombie, then the default action will be to *fob*,", + "i.e allow the ecflow client command to complete without an error", + "The default can be overridden by using zombie attributes.", + "", + "Usage:", + " ecflow_client --event=ev # set the event, default since event initial value is clear", + " ecflow_client --event=ev set # set the event, explicit", + " ecflow_client --event=ev clear # clear the event, use when event initial value is set", + "" ], "arguments": [ { @@ -307,7 +597,13 @@ "implementation": "CFileCmd", "summary": "Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ]", "description": [ - "Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ]\nBy default will return the script.\n arg1 = path to node\n arg2 = (optional) [ script | job | jobout | manual | kill | stat ]\n kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill\n stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat\n arg3 = (optional) max_lines = 10000 " + "Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ]", + "By default will return the script.", + " arg1 = path to node", + " arg2 = (optional) [ script | job | jobout | manual | kill | stat ]", + " kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill", + " stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat", + " arg3 = (optional) max_lines = 10000 " ] }, { @@ -317,8 +613,35 @@ "implementation": "ForceCmd", "summary": "Force a node to a given state, or set its event.", "description": [ - "Force a node to a given state, or set its event.\nWhen a task is set to complete, it may be automatically re-queued if it has\nmultiple future time dependencies. However each time we force a complete it will\nexpire any time based attribute on that node. When the last time based attribute\nexpires, the node will stay in a complete state.\nThis behaviour allow Repeat values to be incremented interactively.\nA repeat attribute is incremented when all the child nodes are complete\nin this case the child nodes are automatically re-queued.\n arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ]\n arg2 = (optional) recursive\n Applies state to node and recursively to all its children\n arg3 = (optional) full\n Set repeat variables to last value, only works in conjunction\n with recursive option\n arg4 = path_to_node or path_to_node:: paths must begin with '/'\nUsage:\n --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete\n --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task\n --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1\nEffect:\n Consider the effect of forcing complete when the current time is at 09:00\n suite s1\n task t1; time 12:00 # will complete straight away\n task t2; time 10:00 13:00 01:00 # will complete on fourth attempt", - " --force=complete /s1/t1 /s1/t2\n When we have a time range(i.e as shown with task t2), it is re-queued and the\n next time slot is incremented for each complete, until it expires, and the task completes.\n Use the Why command, to show next run time (i.e. next time slot)" + "Force a node to a given state, or set its event.", + "When a task is set to complete, it may be automatically re-queued if it has", + "multiple future time dependencies. However each time we force a complete it will", + "expire any time based attribute on that node. When the last time based attribute", + "expires, the node will stay in a complete state.", + "This behaviour allow Repeat values to be incremented interactively.", + "A repeat attribute is incremented when all the child nodes are complete", + "in this case the child nodes are automatically re-queued.", + " arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ]", + " arg2 = (optional) recursive", + " Applies state to node and recursively to all its children", + " arg3 = (optional) full", + " Set repeat variables to last value, only works in conjunction", + " with recursive option", + " arg4 = path_to_node or path_to_node:: paths must begin with '/'", + "Usage:", + " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete", + " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task", + " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1", + "Effect:", + " Consider the effect of forcing complete when the current time is at 09:00", + " suite s1", + " task t1; time 12:00 # will complete straight away", + " task t2; time 10:00 13:00 01:00 # will complete on fourth attempt", + "", + " --force=complete /s1/t1 /s1/t2", + " When we have a time range(i.e as shown with task t2), it is re-queued and the", + " next time slot is incremented for each complete, until it expires, and the task completes.", + " Use the Why command, to show next run time (i.e. next time slot)" ] }, { @@ -336,7 +659,21 @@ "implementation": "FreeDepCmd", "summary": "Free dependencies for a node. Defaults to triggers", "description": [ - "Free dependencies for a node. Defaults to triggers\nAfter freeing the time related dependencies (i.e time,today,cron)\nthe next time slot will be missed.\n arg1 = (optional) trigger\n arg2 = (optional) all\n Free trigger, date and all time dependencies\n arg3 = (optional) date\n Free date dependencies\n arg4 = (optional) time\n Free all time dependencies i.e time, day, today, cron\n arg5 = List of paths. At least one required. Must start with a leading '/'\nUsage:\n --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2\n --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1\n --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1" + "Free dependencies for a node. Defaults to triggers", + "After freeing the time related dependencies (i.e time,today,cron)", + "the next time slot will be missed.", + " arg1 = (optional) trigger", + " arg2 = (optional) all", + " Free trigger, date and all time dependencies", + " arg3 = (optional) date", + " Free date dependencies", + " arg4 = (optional) time", + " Free all time dependencies i.e time, day, today, cron", + " arg5 = List of paths. At least one required. Must start with a leading '/'", + "Usage:", + " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2", + " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1", + " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1" ] }, { @@ -346,7 +683,13 @@ "implementation": "CtsNodeCmd", "summary": "Get the suite definition or node tree in form that is re-parse able", "description": [ - "Get the suite definition or node tree in form that is re-parse able\nGet all suite node tree's from the server and write to standard out.\nThe output is parse-able, and can be used to re-load the definition\n arg = NULL | arg = node path\nUsage:\n --get # gets the definition from the server,and writes to standard out\n --get=/s1 # gets the suite from the server,and writes to standard out" + "Get the suite definition or node tree in form that is re-parse able", + "Get all suite node tree's from the server and write to standard out.", + "The output is parse-able, and can be used to re-load the definition", + " arg = NULL | arg = node path", + "Usage:", + " --get # gets the definition from the server,and writes to standard out", + " --get=/s1 # gets the suite from the server,and writes to standard out" ] }, { @@ -356,7 +699,13 @@ "implementation": "CtsNodeCmd", "summary": "Get state data. For the whole suite definition or individual nodes.", "description": [ - "Get state data. For the whole suite definition or individual nodes.\nThis will include event, meter, node state, trigger and time state.\nThe output is written to standard out.\n arg = NULL | arg = node path\nUsage:\n --get_state # gets the definition from the server,and writes to standard out\n --get_state=/s1 # gets the suite from the server,and writes to standard out" + "Get state data. For the whole suite definition or individual nodes.", + "This will include event, meter, node state, trigger and time state.", + "The output is written to standard out.", + " arg = NULL | arg = node path", + "Usage:", + " --get_state # gets the definition from the server,and writes to standard out", + " --get_state=/s1 # gets the suite from the server,and writes to standard out" ] }, { @@ -366,7 +715,16 @@ "implementation": "GroupCTSCmd", "summary": "Allows a series of ';' separated commands to be grouped and executed as one.", "description": [ - "Allows a series of ';' separated commands to be grouped and executed as one.\nSome commands like halt, shutdown and terminate will prompt the user. To bypass the prompt\nprovide 'yes' as an additional parameter. See example below.\n arg = string\nUsage:\n --group=\"halt=yes; reloadwsfile; restart;\"\n # halt server,bypass the confirmation prompt,\n # reload white list file, restart server\n --group=\"get; show\" # get server defs, and write to standard output\n --group=\"get=/s1; show state\" # get suite 's1', and write state to standard output" + "Allows a series of ';' separated commands to be grouped and executed as one.", + "Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt", + "provide 'yes' as an additional parameter. See example below.", + " arg = string", + "Usage:", + " --group=\"halt=yes; reloadwsfile; restart;\"", + " # halt server,bypass the confirmation prompt,", + " # reload white list file, restart server", + " --group=\"get; show\" # get server defs, and write to standard output", + " --group=\"get=/s1; show state\" # get suite 's1', and write state to standard output" ] }, { @@ -376,7 +734,18 @@ "implementation": "CtsCmd", "summary": "Stop server communication with jobs, and new job scheduling.", "description": [ - "Stop server communication with jobs, and new job scheduling.\nAlso stops automatic check pointing\n arg1 = yes(optional) # use to bypass confirmation prompt,i.e.\n --halt=yes\nThe following table shows server behaviour in the different states.\n|----------------------------------------------------------------------------------|\n| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n|--------------|--------------|--------------|---------------|---------------------|\n| RUNNING | yes | yes | yes | yes |\n| SHUTDOWN | yes | yes | no | yes |\n| HALTED | yes | no | no | no |\n|--------------|--------------|--------------|---------------|---------------------|" + "Stop server communication with jobs, and new job scheduling.", + "Also stops automatic check pointing", + " arg1 = yes(optional) # use to bypass confirmation prompt,i.e.", + " --halt=yes", + "The following table shows server behaviour in the different states.", + "|----------------------------------------------------------------------------------|", + "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |", + "|--------------|--------------|--------------|---------------|---------------------|", + "| RUNNING | yes | yes | yes | yes |", + "| SHUTDOWN | yes | yes | no | yes |", + "| HALTED | yes | no | no | no |", + "|--------------|--------------|--------------|---------------|---------------------|" ] }, { @@ -386,9 +755,19 @@ "implementation": "InitCmd", "summary": "Mark task as started(active). For use in the '.ecf' script file *only*", "description": [ - "Mark task as started(active). For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables.\n arg1(string) = process_or_remote_id The process id of the job or remote_id\n Using remote id allows the jobs to be killed\n arg2(--add)(optional)= add/update variables as name value pairs", - "If this task command is a zombie, then the default action will be to *block*.\nThe default can be overridden by using zombie attributes.\nOtherwise the blocking period is defined by ECF_TIMEOUT.", - "Usage:\n ecflow_client --init=$$\n ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" + "Mark task as started(active). For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables.", + " arg1(string) = process_or_remote_id The process id of the job or remote_id", + " Using remote id allows the jobs to be killed", + " arg2(--add)(optional)= add/update variables as name value pairs", + "", + "If this task command is a zombie, then the default action will be to *block*.", + "The default can be overridden by using zombie attributes.", + "Otherwise the blocking period is defined by ECF_TIMEOUT.", + "", + "Usage:", + " ecflow_client --init=$$", + " ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ], "arguments": [ { @@ -415,7 +794,12 @@ "implementation": "CtsNodeCmd", "summary": "Job submission for chosen Node *based* on dependencies.", "description": [ - "Job submission for chosen Node *based* on dependencies.\nThe server traverses the node tree every 60 seconds, and if the dependencies are free\ndoes job generation and submission. Sometimes the user may free time/date dependencies\nto avoid waiting for the server poll, this commands allows early job generation\n arg = node path | arg = NULL\n If no node path specified generates for full definition." + "Job submission for chosen Node *based* on dependencies.", + "The server traverses the node tree every 60 seconds, and if the dependencies are free", + "does job generation and submission. Sometimes the user may free time/date dependencies", + "to avoid waiting for the server poll, this commands allows early job generation", + " arg = node path | arg = NULL", + " If no node path specified generates for full definition." ] }, { @@ -425,7 +809,15 @@ "implementation": "PathsCmd", "summary": "Kills the job associated with the node.", "description": [ - "Kills the job associated with the node.\nIf a family or suite is selected, will kill hierarchically.\nKill uses the ECF_KILL_CMD variable. After variable substitution it is invoked as a command.\nThe command should be written in such a way that the output is written to %ECF_JOB%.kill\nas this allow the --file command to report the output: .e.e.\n /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::\nUsage::\n --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2\n --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1" + "Kills the job associated with the node.", + "If a family or suite is selected, will kill hierarchically.", + "Kill uses the ECF_KILL_CMD variable. After variable substitution it is invoked as a command.", + "The command should be written in such a way that the output is written to %ECF_JOB%.kill", + "as this allow the --file command to report the output: .e.e.", + " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::", + "Usage::", + " --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2", + " --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1" ] }, { @@ -435,9 +827,18 @@ "implementation": "LabelCmd", "summary": "Change Label. For use in the '.ecf' script file *only*", "description": [ - "Change Label. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1 = label-name\n arg2 = The new label value\n The labels values can be single or multi-line(space separated quoted strings)", - "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", - "Usage:\n ecflow_client --label=progressed merlin" + "Change Label. For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables", + " arg1 = label-name", + " arg2 = The new label value", + " The labels values can be single or multi-line(space separated quoted strings)", + "", + "If this task command is a zombie, then the default action will be to *fob*,", + "i.e allow the ecflow client command to complete without an error", + "The default can be overridden by using zombie attributes.", + "", + "Usage:", + " ecflow_client --label=progressed merlin" ], "arguments": [ { @@ -459,7 +860,23 @@ "implementation": "LoadDefsCmd", "summary": "Check and load definition or checkpoint file into server.", "description": [ - "Check and load definition or checkpoint file into server.\nThe loaded definition will be checked for valid trigger and complete expressions,\nadditionally in-limit references to limits will be validated.\nIf the server already has the 'suites' of the same name, then a error message is issued.\nThe suite's can be overwritten if the force option is used.\nTo just check the definition and not send to server, use 'check_only'\nThis command can also be used to load a checkpoint file into the server\n arg1 = path to the definition file or checkpoint file\n arg2 = (optional) [ force | check_only | print | stats ] # default = false for all\nUsage:\n--load=/my/home/exotic.def # will error if suites of same name exists\n--load=/my/home/exotic.def force # overwrite suite's of same name in the server\n--load=/my/home/exotic.def check_only # Just check, don't send to server\n--load=/my/home/exotic.def stats # Show defs statistics, don't send to server\n--load=host1.3141.check # Load checkpoint file to the server\n--load=host1.3141.check print # print definition to standard out in defs format\n" + "Check and load definition or checkpoint file into server.", + "The loaded definition will be checked for valid trigger and complete expressions,", + "additionally in-limit references to limits will be validated.", + "If the server already has the 'suites' of the same name, then a error message is issued.", + "The suite's can be overwritten if the force option is used.", + "To just check the definition and not send to server, use 'check_only'", + "This command can also be used to load a checkpoint file into the server", + " arg1 = path to the definition file or checkpoint file", + " arg2 = (optional) [ force | check_only | print | stats ] # default = false for all", + "Usage:", + "--load=/my/home/exotic.def # will error if suites of same name exists", + "--load=/my/home/exotic.def force # overwrite suite's of same name in the server", + "--load=/my/home/exotic.def check_only # Just check, don't send to server", + "--load=/my/home/exotic.def stats # Show defs statistics, don't send to server", + "--load=host1.3141.check # Load checkpoint file to the server", + "--load=host1.3141.check print # print definition to standard out in defs format", + "" ] }, { @@ -469,7 +886,36 @@ "implementation": "LogCmd", "summary": "Get,clear,flush or create a new log file.", "description": [ - "Get,clear,flush or create a new log file.\nThe user must ensure that a valid path is specified.\nSpecifying '--log=get' with a large number of lines from the server,\ncan consume a lot of **memory**. The log file can be a very large file,\nhence we use a default of 100 lines, optionally the number of lines can be specified.\n arg1 = [ get | clear | flush | new | path ]\n get - Outputs the log file to standard out.\n defaults to return the last 100 lines\n The second argument can specify how many lines to return\n clear - Clear the log file of its contents.\n flush - Flush and close the log file. (only temporary) next time\n server writes to log, it will be opened again. Hence it best\n to halt the server first\n new - Flush and close the existing log file, and start using the\n the path defined for ECF_LOG. By changing this variable\n a new log file path can be used\n Alternatively an explicit path can also be provided\n in which case ECF_LOG is also updated\n path - Returns the path name to the existing log file\n arg2 = [ new_path | optional last n lines ]\n if get specified can specify lines to get. Value must be convertible to an integer\n Otherwise if arg1 is 'new' then the second argument must be a path\nUsage:\n --log=get # Write the last 100 lines of the log file to standard out\n --log=get 200 # Write the last 200 lines of the log file to standard out\n --log=clear # Clear the log file. The log is now empty\n --log=flush # Flush and close log file, next request will re-open log file\n --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG\n --log=new # Close and flush log file, and create a new log file using ECF_LOG variable\n" + "Get,clear,flush or create a new log file.", + "The user must ensure that a valid path is specified.", + "Specifying '--log=get' with a large number of lines from the server,", + "can consume a lot of **memory**. The log file can be a very large file,", + "hence we use a default of 100 lines, optionally the number of lines can be specified.", + " arg1 = [ get | clear | flush | new | path ]", + " get - Outputs the log file to standard out.", + " defaults to return the last 100 lines", + " The second argument can specify how many lines to return", + " clear - Clear the log file of its contents.", + " flush - Flush and close the log file. (only temporary) next time", + " server writes to log, it will be opened again. Hence it best", + " to halt the server first", + " new - Flush and close the existing log file, and start using the", + " the path defined for ECF_LOG. By changing this variable", + " a new log file path can be used", + " Alternatively an explicit path can also be provided", + " in which case ECF_LOG is also updated", + " path - Returns the path name to the existing log file", + " arg2 = [ new_path | optional last n lines ]", + " if get specified can specify lines to get. Value must be convertible to an integer", + " Otherwise if arg1 is 'new' then the second argument must be a path", + "Usage:", + " --log=get # Write the last 100 lines of the log file to standard out", + " --log=get 200 # Write the last 200 lines of the log file to standard out", + " --log=clear # Clear the log file. The log is now empty", + " --log=flush # Flush and close log file, next request will re-open log file", + " --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG", + " --log=new # Close and flush log file, and create a new log file using ECF_LOG variable", + "" ] }, { @@ -479,9 +925,17 @@ "implementation": "MeterCmd", "summary": "Change meter. For use in the '.ecf' script file *only*", "description": [ - "Change meter. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string) = meter-name\n arg2(int) = the new meter value", - "If this task command is a zombie, then the default action will be to *fob*,\ni.e allow the ecflow client command to complete without an error\nThe default can be overridden by using zombie attributes.", - "Usage:\n ecflow_client --meter=my_meter 20" + "Change meter. For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables", + " arg1(string) = meter-name", + " arg2(int) = the new meter value", + "", + "If this task command is a zombie, then the default action will be to *fob*,", + "i.e allow the ecflow client command to complete without an error", + "The default can be overridden by using zombie attributes.", + "", + "Usage:", + " ecflow_client --meter=my_meter 20" ], "arguments": [ { @@ -504,9 +958,24 @@ "implementation": "CtsNodeCmd", "summary": "Used to print state of the definition returned from the server to standard output.", "description": [ - "Used to print state of the definition returned from the server to standard output.\nThe node state is shown in the comments.\nThis is the format used in the check point file, but with indentation.\nSince this is essentially the defs format with state in the comments,it allows the definition to be migrated to future version of ecflow.\nThe output includes edit history but excludes externs.\nWhen the definition is reloaded *NO* checking is done.", - "The following shows a summary of the features associated with each choice:\n --get --get_state --migrate\nAuto generate externs Yes Yes No\nChecking on reload Yes Yes No\nEdit History No No Yes\nShow trigger AST No Yes No", - "Usage:\n --migrate # show all suites\n --migrate=/s1 # show state for suite s1\n" + "Used to print state of the definition returned from the server to standard output.", + "The node state is shown in the comments.", + "This is the format used in the check point file, but with indentation.", + "Since this is essentially the defs format with state in the comments,it allows the definition to be migrated to future version of ecflow.", + "The output includes edit history but excludes externs.", + "When the definition is reloaded *NO* checking is done.", + "", + "The following shows a summary of the features associated with each choice:", + " --get --get_state --migrate", + "Auto generate externs Yes Yes No", + "Checking on reload Yes Yes No", + "Edit History No No Yes", + "Show trigger AST No Yes No", + "", + "Usage:", + " --migrate # show all suites", + " --migrate=/s1 # show state for suite s1", + "" ] }, { @@ -515,9 +984,7 @@ "visibility": "internal", "implementation": "MoveCmd", "summary": "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api.", - "description": [ - "The move command is an internal cmd, Called by the plug cmd. Does not appear on public api." - ] + "description": ["The move command is an internal cmd, Called by the plug cmd. Does not appear on public api."] }, { "name": "msg", @@ -526,7 +993,10 @@ "implementation": "LogMessageCmd", "summary": "Writes the input string to the log file.", "description": [ - "Writes the input string to the log file.\n arg1 = string\nUsage:\n --msg=\"place me in the log file\"" + "Writes the input string to the log file.", + " arg1 = string", + "Usage:", + " --msg=\"place me in the log file\"" ] }, { @@ -536,7 +1006,11 @@ "implementation": "CSyncCmd", "summary": "Returns true if state of server definition changed.", "description": [ - "Returns true if state of server definition changed.\n*Important* for use with c++/python interface only.\nRequires Given a client handle, change and modify number determine if server changed since last call\nThis relies on user calling sync after news to update the locally stored modify and change numbers.\nThese numbers are then used in the next call to news." + "Returns true if state of server definition changed.", + "*Important* for use with c++/python interface only.", + "Requires Given a client handle, change and modify number determine if server changed since last call", + "This relies on user calling sync after news to update the locally stored modify and change numbers.", + "These numbers are then used in the next call to news." ] }, { @@ -546,10 +1020,29 @@ "implementation": "OrderNodeCmd", "summary": "Re-orders the nodes held by the server", "description": [ - "Re-orders the nodes held by the server\n arg1 = node path\n arg2 = [ top | bottom | alpha | order | up | down | runtime]\nIt should be noted that in the absence of triggers and time/date dependencies,\nthe tasks are submitted in order.\nThis changes the order and hence affects the submission order::", - " o top raises the node within its parent, so that it is first\n o bottom lowers the node within its parent, so that it is last\n o alpha Arranges for all the peers of selected note to be sorted alphabetically (case-insensitive)\n o order Arranges for all the peers of selected note to be sorted in reverse alphabet(case-insensitive)\n o up Moves the selected node up one place amongst its peers\n o down Moves the selected node down one place amongst its peers", - " o runtime Orders the nodes according to state change runtime\n for families by accumulated runtime of its children\n useful to submit the task that take longer earlier", - "This command can fail because:\n- The node path does not exist in the server\n- The order_type is not does not match one of arg2\nUsage:\n --order=/suite/f1 top # move node f1 to the top" + "Re-orders the nodes held by the server", + " arg1 = node path", + " arg2 = [ top | bottom | alpha | order | up | down | runtime]", + "It should be noted that in the absence of triggers and time/date dependencies,", + "the tasks are submitted in order.", + "This changes the order and hence affects the submission order::", + "", + " o top raises the node within its parent, so that it is first", + " o bottom lowers the node within its parent, so that it is last", + " o alpha Arranges for all the peers of selected note to be sorted alphabetically (case-insensitive)", + " o order Arranges for all the peers of selected note to be sorted in reverse alphabet(case-insensitive)", + " o up Moves the selected node up one place amongst its peers", + " o down Moves the selected node down one place amongst its peers", + "", + " o runtime Orders the nodes according to state change runtime", + " for families by accumulated runtime of its children", + " useful to submit the task that take longer earlier", + "", + "This command can fail because:", + "- The node path does not exist in the server", + "- The order_type is not does not match one of arg2", + "Usage:", + " --order=/suite/f1 top # move node f1 to the top" ] }, { @@ -559,7 +1052,14 @@ "implementation": "CtsCmd", "summary": "Check if server is running on given host/port. Result reported to standard output.", "description": [ - "Check if server is running on given host/port. Result reported to standard output.\nUsage:\n --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144\n --ping --host=fred # Check if server alive on host fred and port ECF_PORT,\n # otherwise default port of 3141\n --ping # Check if server alive by using environment variables\n # ECF_HOST and ECF_PORT\nIf ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141" + "Check if server is running on given host/port. Result reported to standard output.", + "Usage:", + " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144", + " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,", + " # otherwise default port of 3141", + " --ping # Check if server alive by using environment variables", + " # ECF_HOST and ECF_PORT", + "If ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141" ] }, { @@ -569,7 +1069,21 @@ "implementation": "PlugCmd", "summary": "Plug command is used to move nodes.", "description": [ - "Plug command is used to move nodes.\nThe destination node can be on another server In which case the destination\npath should be of the form ':/suite/family/task\n arg1 = path to source node\n arg2 = path to the destination node\nThis command can fail because:\n- Source node is in a 'active' or 'submitted' state\n- Another user already has an lock\n- source/destination paths do not exist on the corresponding servers\n- If the destination node path is empty, i.e. only host:port is specified,\n then the source node must correspond to a suite.\n- If the source node is added as a child, then its name must be unique\n amongst its peers\nUsage:\n --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)" + "Plug command is used to move nodes.", + "The destination node can be on another server In which case the destination", + "path should be of the form ':/suite/family/task", + " arg1 = path to source node", + " arg2 = path to the destination node", + "This command can fail because:", + "- Source node is in a 'active' or 'submitted' state", + "- Another user already has an lock", + "- source/destination paths do not exist on the corresponding servers", + "- If the destination node path is empty, i.e. only host:port is specified,", + " then the source node must correspond to a suite.", + "- If the source node is added as a child, then its name must be unique", + " amongst its peers", + "Usage:", + " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)" ] }, { @@ -579,9 +1093,54 @@ "implementation": "QueryCmd", "summary": "Query the status of attributes", "description": [ - "Query the status of attributes\n i.e state,dstate,repeat,event,meter,label,variable or trigger expression without blocking\n - state return [unknown | complete | queued | aborted | submitted | active] to standard out\n - dstate return [unknown | complete | queued | suspended | aborted | submitted | active] to standard out\n - repeat returns current value as a string to standard out\n - event return 'set' | 'clear' to standard out\n - meter return value of the meter to standard out\n - limit return current value of limit to standard out\n - limit_max return limit max value to standard out\n - label return new value otherwise the old value\n - variable return value of the variable, repeat or generated variable to standard out,\n will search up the node tree. When path is '/', the variable is looked up on the\n server itself, i.e. 'ecflow_client --query variable /:name'\n - trigger returns 'true' if the expression is true, otherwise 'false'", - "If this command is called within a '.ecf' script we will additionally log the task calling this command\nThis is required to aid debugging for excessive use of this command\nThe command will fail if the node path to the attribute does not exist in the definition and if:\n - repeat The repeat is not found\n - event The event is not found\n - meter The meter is not found\n - limit/limit_max The limit is not found\n - label The label is not found\n - variable No user or generated variable or repeat of that name found on node or its parents,\n or (when path is '/') no user or server variable of that name found on the server\n - trigger Trigger does not parse, or reference to nodes/attributes in the expression are not valid\nArguments:\n arg1 = [ state | dstate | repeat | event | meter | label | variable | trigger | limit | limit_max ]\n arg2 = | :name where name is name of a event, meter, label, limit or variable.\n path '/' represents the server itself, and can only be used with 'state' or 'variable'\n arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat", - "Usage:\n ecflow_client --query state / # return top level state to standard out\n ecflow_client --query state /path/to/node # return node state to standard out\n ecflow_client --query dstate /path/to/node # state that can included suspended\n ecflow_client --query repeat /path/to/node # return the current value as a string\n ecflow_client --query repeat /path/to/node prev # return the previous value as a string\n ecflow_client --query repeat /path/to/node next # return the next value as a string\n ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out\n ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out\n ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out\n ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out\n ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out\n ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to standard out\n ecflow_client --query variable /:var_name # returns the server variable value to standard out\n ecflow_client --query trigger /path/to/node/with/trigger \"/suite/task == complete\" # return true if expression evaluates false otherwise\n" + "Query the status of attributes", + " i.e state,dstate,repeat,event,meter,label,variable or trigger expression without blocking", + " - state return [unknown | complete | queued | aborted | submitted | active] to standard out", + " - dstate return [unknown | complete | queued | suspended | aborted | submitted | active] to standard out", + " - repeat returns current value as a string to standard out", + " - event return 'set' | 'clear' to standard out", + " - meter return value of the meter to standard out", + " - limit return current value of limit to standard out", + " - limit_max return limit max value to standard out", + " - label return new value otherwise the old value", + " - variable return value of the variable, repeat or generated variable to standard out,", + " will search up the node tree. When path is '/', the variable is looked up on the", + " server itself, i.e. 'ecflow_client --query variable /:name'", + " - trigger returns 'true' if the expression is true, otherwise 'false'", + "", + "If this command is called within a '.ecf' script we will additionally log the task calling this command", + "This is required to aid debugging for excessive use of this command", + "The command will fail if the node path to the attribute does not exist in the definition and if:", + " - repeat The repeat is not found", + " - event The event is not found", + " - meter The meter is not found", + " - limit/limit_max The limit is not found", + " - label The label is not found", + " - variable No user or generated variable or repeat of that name found on node or its parents,", + " or (when path is '/') no user or server variable of that name found on the server", + " - trigger Trigger does not parse, or reference to nodes/attributes in the expression are not valid", + "Arguments:", + " arg1 = [ state | dstate | repeat | event | meter | label | variable | trigger | limit | limit_max ]", + " arg2 = | :name where name is name of a event, meter, label, limit or variable.", + " path '/' represents the server itself, and can only be used with 'state' or 'variable'", + " arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat", + "", + "Usage:", + " ecflow_client --query state / # return top level state to standard out", + " ecflow_client --query state /path/to/node # return node state to standard out", + " ecflow_client --query dstate /path/to/node # state that can included suspended", + " ecflow_client --query repeat /path/to/node # return the current value as a string", + " ecflow_client --query repeat /path/to/node prev # return the previous value as a string", + " ecflow_client --query repeat /path/to/node next # return the next value as a string", + " ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out", + " ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out", + " ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out", + " ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out", + " ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out", + " ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to standard out", + " ecflow_client --query variable /:var_name # returns the server variable value to standard out", + " ecflow_client --query trigger /path/to/node/with/trigger \"/suite/task == complete\" # return true if expression evaluates false otherwise", + "" ] }, { @@ -591,10 +1150,37 @@ "implementation": "QueueCmd", "summary": "QueueCmd. For use in the '.ecf' script file *only*", "description": [ - "QueueCmd. For use in the '.ecf' script file *only*\nHence the context is supplied via environment variables\n arg1(string) = queue-name:\n arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ]\n active: returns the first queued/aborted step, the return string is the queue value from the definition\n no_of_aborted: returns number of aborted steps as a string, i.e 10\n reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors\n arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active)\n This is only valid for complete and aborted steps\n arg4(string) = path: (optional). The path where the queue is defined.\n By default we search for the queue up the node tree.", - "If this task command is a zombie, then the default action will be to *block*,\nThe default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will\nsearch for the queue up the node hierarchy. If no queue found, command fails", - "Usage:\nstep=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone", - "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }\n" + "QueueCmd. For use in the '.ecf' script file *only*", + "Hence the context is supplied via environment variables", + " arg1(string) = queue-name:", + " arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ]", + " active: returns the first queued/aborted step, the return string is the queue value from the definition", + " no_of_aborted: returns number of aborted steps as a string, i.e 10", + " reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors", + " arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active)", + " This is only valid for complete and aborted steps", + " arg4(string) = path: (optional). The path where the queue is defined.", + " By default we search for the queue up the node tree.", + "", + "If this task command is a zombie, then the default action will be to *block*,", + "The default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will", + "search for the queue up the node hierarchy. If no queue found, command fails", + "", + "Usage:", + "step=\"\"", + "QNAME=\"my_queue_name\"", + "while [1 == 1 ] ; do", + " # this return the first queued/aborted step, then increments to next step, return when all steps processed", + " step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active", + " if [[ $step == \"\" ]] ; then", + " break;", + " fi", + " ...", + " ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed", + "done", + "", + "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }", + "" ], "arguments": [ { @@ -633,18 +1219,53 @@ "summary": "Reload the server custom password file.", "description": [ "Reload the server custom password file.", - "The custom password file (authentication) is used by the server to authenticate a 'user' by\nverifying if the password provided by the user matches the one held by the server. This\nparticular file is used for authentication of users that explicitly specify the user name\n(either via the environment variable ECF_USER or the --user option).", - "This mechanism should be used when most users use the machine login name, but a few users\nspecify their own user name, in which case the password must also be explicitly provided.", - "The file path is specified as the ECF_CUSTOM_PASSWD environment variable, both for the\nclient and server, and is loaded only by the server on *startup*. This means that the file\ncontents can be updated (i.e., add/remove users), but the file location cannot change during\nthe server execution.", + "", + "The custom password file (authentication) is used by the server to authenticate a 'user' by", + "verifying if the password provided by the user matches the one held by the server. This", + "particular file is used for authentication of users that explicitly specify the user name", + "(either via the environment variable ECF_USER or the --user option).", + "", + "This mechanism should be used when most users use the machine login name, but a few users", + "specify their own user name, in which case the password must also be explicitly provided.", + "", + "The file path is specified as the ECF_CUSTOM_PASSWD environment variable, both for the", + "client and server, and is loaded only by the server on *startup*. This means that the file", + "contents can be updated (i.e., add/remove users), but the file location cannot change during", + "the server execution.", + "", "The server automatically loads the password file content as part of the startup procedure.", - "The ECF_CUSTOM_PASSWD environment variable is used to specify the password file location,\nconsidering that\n - On the server the default file name is ..ecf.custom_passwd\n - On the client the default file name is ecf.custom_passwd", + "", + "The ECF_CUSTOM_PASSWD environment variable is used to specify the password file location,", + "considering that", + " - On the server the default file name is ..ecf.custom_passwd", + " - On the client the default file name is ecf.custom_passwd", + "", "The format of the file is same for client and server:", - "\n4.5.0\n# comment\n # comment", + "", + "", + "4.5.0", + "# comment", + " # comment", + "", "The following is an example", - "4.5.0 # the version\nfred machine1 3142 xxyyyd\nfred machine2 3133 xxyyyd # comment\nbill machine2 3133 xxyggyyd", - "Notice that the same user may appear multiple times (associated with different host/port).\nThis allows the client to use the same password file to contact multiple servers.", - "For the password authentication to work, ensure the following:\n - The password is defined for the client and server\n - On the server, add at least the server administrator to the password file\n Note: If an empty password file (i.e., containing just the version) is used,\n no user is allowed access.\n - On the client, the password file should be readable only by the 'user' itself", - "Usage:\n --reloadcustompasswdfile" + "", + "4.5.0 # the version", + "fred machine1 3142 xxyyyd", + "fred machine2 3133 xxyyyd # comment", + "bill machine2 3133 xxyggyyd", + "", + "Notice that the same user may appear multiple times (associated with different host/port).", + "This allows the client to use the same password file to contact multiple servers.", + "", + "For the password authentication to work, ensure the following:", + " - The password is defined for the client and server", + " - On the server, add at least the server administrator to the password file", + " Note: If an empty password file (i.e., containing just the version) is used,", + " no user is allowed access.", + " - On the client, the password file should be readable only by the 'user' itself", + "", + "Usage:", + " --reloadcustompasswdfile" ] }, { @@ -655,18 +1276,53 @@ "summary": "Reload the server password file.", "description": [ "Reload the server password file.", - "The password file (authentication) is used by the server to authenticate a 'user' by\nverifying if the password provided by the user matches the one held by the server.\nThe password file is also used on the client to automatically load the password for the\n'user' when connecting to the server.", + "", + "The password file (authentication) is used by the server to authenticate a 'user' by", + "verifying if the password provided by the user matches the one held by the server.", + "The password file is also used on the client to automatically load the password for the", + "'user' when connecting to the server.", + "", "When the server is configured to use a password file, then ALL users must have a password.", - "The file path is specified as the ECF_PASSWD environment variable, both for the client and\nserver, and is loaded only by the server on *startup*. This means that the file contents\ncan be updated (i.e., add/remove users), but the file location cannot change during the\nserver execution.", + "", + "The file path is specified as the ECF_PASSWD environment variable, both for the client and", + "server, and is loaded only by the server on *startup*. This means that the file contents", + "can be updated (i.e., add/remove users), but the file location cannot change during the", + "server execution.", + "", "The server automatically loads the password file content as part of the startup procedure.", - "The ECF_PASSWD environment variable is used to specify the password file location,\nconsidering that\n - On the server, the default file name is ..ecf.passwd\n - On the client, the default file name is ecf.passwd", + "", + "The ECF_PASSWD environment variable is used to specify the password file location,", + "considering that", + " - On the server, the default file name is ..ecf.passwd", + " - On the client, the default file name is ecf.passwd", + "", "The format of the file is same for client and server:", - "\n4.5.0\n# comment\n # comment", + "", + "", + "4.5.0", + "# comment", + " # comment", + "", "The following is an example", - "4.5.0 # the version\nfred machine1 3142 xxyyyd\nfred machine2 3133 xxyyyd # comment\nbill machine2 3133 xxyggyyd", - "\nNotice that the same user may appear multiple times (associated with different host/port).\nThis allows the client to use the same password file to contact multiple servers.", - "For the password authentication to work, ensure the following:\n - The password is defined for the client and server\n - On the server, add at least the server administrator to the password file\n Note: If an empty password file (i.e., containing just the version) is used,\n no user is allowed access.\n - On the client, the password file should be readable only by the 'user' itself", - "Usage:\n --reloadpasswdfile" + "", + "4.5.0 # the version", + "fred machine1 3142 xxyyyd", + "fred machine2 3133 xxyyyd # comment", + "bill machine2 3133 xxyggyyd", + "", + "", + "Notice that the same user may appear multiple times (associated with different host/port).", + "This allows the client to use the same password file to contact multiple servers.", + "", + "For the password authentication to work, ensure the following:", + " - The password is defined for the client and server", + " - On the server, add at least the server administrator to the password file", + " Note: If an empty password file (i.e., containing just the version) is used,", + " no user is allowed access.", + " - On the client, the password file should be readable only by the 'user' itself", + "", + "Usage:", + " --reloadpasswdfile" ] }, { @@ -677,16 +1333,46 @@ "summary": "Reload the white list file.", "description": [ "Reload the white list file.", - "The white list file (authorisation) is used to verify if a 'user' is allowed to perform a\nspecific command.", - "The file path is specified as the ECF_LISTS variable, and loaded only once by the server\n(on *startup*). This means that the file contents can be updated, but the file location\ncannot change during the server execution.", - "The ECF_LISTS variable can be used as follows:\n - if ECF_LISTS is not specified, or if it is specified with value `ecf.lists`,\n then the server will use the value `..ecf.lists`\n - if ECF_LISTS is specified to be a path, such as /var/tmp/ecf.lists,\n then the server will use this path to reload the white list file", - "The server automatically loads the white list file content as part of the startup procedure,\nconsidering that if the file is not present or is empty (i.e., just contains the version\nnumber) then all users have read/write access.", + "", + "The white list file (authorisation) is used to verify if a 'user' is allowed to perform a", + "specific command.", + "", + "The file path is specified as the ECF_LISTS variable, and loaded only once by the server", + "(on *startup*). This means that the file contents can be updated, but the file location", + "cannot change during the server execution.", + "", + "The ECF_LISTS variable can be used as follows:", + " - if ECF_LISTS is not specified, or if it is specified with value `ecf.lists`,", + " then the server will use the value `..ecf.lists`", + " - if ECF_LISTS is specified to be a path, such as /var/tmp/ecf.lists,", + " then the server will use this path to reload the white list file", + "", + "The server automatically loads the white list file content as part of the startup procedure,", + "considering that if the file is not present or is empty (i.e., just contains the version", + "number) then all users have read/write access.", + "", "The reload operation will fail if file does not exist or if the content is invalid.", + "", "Expected format for this file is:", - "\n# all characters after the first # in a line are considered comments and are discarded\n# empty lines are also discarded", - "4.4.14 # the version number is mandatory, even if no users are specified\n# Users with read/write access\nuser1\nuser2 # comment\n* # use this form if you want all users to have read/write access", - "# Users with read access, must have - before user name\n-user3 # comment\n-user4\n-* # use this form if you want all users to have read access", - "\nUsage:\n --reloadwsfile" + "", + "", + "# all characters after the first # in a line are considered comments and are discarded", + "# empty lines are also discarded", + "", + "4.4.14 # the version number is mandatory, even if no users are specified", + "# Users with read/write access", + "user1", + "user2 # comment", + "* # use this form if you want all users to have read/write access", + "", + "# Users with read access, must have - before user name", + "-user3 # comment", + "-user4", + "-* # use this form if you want all users to have read access", + "", + "", + "Usage:", + " --reloadwsfile" ] }, { @@ -696,9 +1382,33 @@ "implementation": "ReplaceNodeCmd", "summary": "Replaces a node in the server, with the given path", "description": [ - "Replaces a node in the server, with the given path\nCan also be used to add nodes in the server\n arg1 = path to node\n must exist in the client defs(arg2). This is also the node we want to\n replace in the server\n arg2 = path to client definition file\n provides the definition of the new node\n arg3 = (optional) [ parent | false ] (default = parent)\n create parent families or suite as needed, when arg1 does not\n exist in the server\n arg4 = (optional) force (default = false) \n Force the replacement even if it causes zombies to be created\nReplace can fail if:\n- The node path(arg1) does not exist in the provided client definition(arg2)\n- The client definition(arg2) must be free of errors\n- If the third argument is not provided, then node path(arg1) must exist in the server\n- Nodes to be replaced are in active/submitted state, in which case arg4(force) can be used", - "Replace will preserve the suspended status, if this is not required please re-queue first\nAfter replace is done, we check trigger expressions. These are reported to standard output.\nIt is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.\nPlease note, you can use --check to check trigger expression and limits in the server.\nFor more information use --help check.", - "Usage:\n --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1\n --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted" + "Replaces a node in the server, with the given path", + "Can also be used to add nodes in the server", + " arg1 = path to node", + " must exist in the client defs(arg2). This is also the node we want to", + " replace in the server", + " arg2 = path to client definition file", + " provides the definition of the new node", + " arg3 = (optional) [ parent | false ] (default = parent)", + " create parent families or suite as needed, when arg1 does not", + " exist in the server", + " arg4 = (optional) force (default = false) ", + " Force the replacement even if it causes zombies to be created", + "Replace can fail if:", + "- The node path(arg1) does not exist in the provided client definition(arg2)", + "- The client definition(arg2) must be free of errors", + "- If the third argument is not provided, then node path(arg1) must exist in the server", + "- Nodes to be replaced are in active/submitted state, in which case arg4(force) can be used", + "", + "Replace will preserve the suspended status, if this is not required please re-queue first", + "After replace is done, we check trigger expressions. These are reported to standard output.", + "It is up to the user to correct invalid trigger expressions, otherwise the tasks will *not* run.", + "Please note, you can use --check to check trigger expression and limits in the server.", + "For more information use --help check.", + "", + "Usage:", + " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1", + " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted" ] }, { @@ -708,8 +1418,20 @@ "implementation": "RequeueNodeCmd", "summary": "Re queues the specified node(s)", "description": [ - "Re queues the specified node(s)\n If any child of the specified node(s) is in a suspended state, this state is cleared\nRepeats are reset to their starting values, relative time attributes are reset.\n arg1 = (optional) [ abort | force ]\n abort = re-queue only aborted tasks below node\n force = Force the re-queueing even if there are nodes that are active or submitted\n = Checks if any tasks are in submitted or active states below the node\n if so does nothing. Otherwise re-queues the node.\n arg2 = list of node paths. The node paths must begin with a leading '/' character", - "Usage:\n --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1\n --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.\n --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'" + "Re queues the specified node(s)", + " If any child of the specified node(s) is in a suspended state, this state is cleared", + "Repeats are reset to their starting values, relative time attributes are reset.", + " arg1 = (optional) [ abort | force ]", + " abort = re-queue only aborted tasks below node", + " force = Force the re-queueing even if there are nodes that are active or submitted", + " = Checks if any tasks are in submitted or active states below the node", + " if so does nothing. Otherwise re-queues the node.", + " arg2 = list of node paths. The node paths must begin with a leading '/' character", + "", + "Usage:", + " --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1", + " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.", + " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'" ] }, { @@ -719,7 +1441,15 @@ "implementation": "CtsCmd", "summary": "Start job scheduling, communication with jobs, and respond to all requests.", "description": [ - "Start job scheduling, communication with jobs, and respond to all requests.\nThe following table shows server behaviour in the different states.\n|----------------------------------------------------------------------------------|\n| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n|--------------|--------------|--------------|---------------|---------------------|\n| RUNNING | yes | yes | yes | yes |\n| SHUTDOWN | yes | yes | no | yes |\n| HALTED | yes | no | no | no |\n|--------------|--------------|--------------|---------------|---------------------|" + "Start job scheduling, communication with jobs, and respond to all requests.", + "The following table shows server behaviour in the different states.", + "|----------------------------------------------------------------------------------|", + "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |", + "|--------------|--------------|--------------|---------------|---------------------|", + "| RUNNING | yes | yes | yes | yes |", + "| SHUTDOWN | yes | yes | no | yes |", + "| HALTED | yes | no | no | no |", + "|--------------|--------------|--------------|---------------|---------------------|" ] }, { @@ -729,10 +1459,33 @@ "implementation": "PathsCmd", "summary": "Manually restore archived nodes.", "description": [ - "Manually restore archived nodes.\nRestore will fail if:\n - Node has not been archived\n - Node has children, (since archived nodes have no children)\n - If the file ECF_HOME/...check does not exist\nNodes can be restored manually(as in this command) but also automatically", - "Automatic restore is done using the 'autorestore' attribute.\nOnce the node containing the 'autorestore' completes, the attribute is applied", - " suite s\n family farchive_now\n autoarchive 0 # archive immediately after complete\n task tx\n endfamily\n family frestore_from_task\n task t1\n trigger ../farchive_nowarchived\n autorestore ../farchive_now # call autorestore when t1 completes\n endfamily\n endsuite", - "In this example task '/s/frestore_from_task/t1' is only triggered if 'farchive_now'\nis archived, then when t1 completes it will restore family 'farchive_now'\nUsage::\n --restore=/s1/f1 # restore family /s1/f1\n --restore=/s1 /s2 # restore suites /s1 and /s2" + "Manually restore archived nodes.", + "Restore will fail if:", + " - Node has not been archived", + " - Node has children, (since archived nodes have no children)", + " - If the file ECF_HOME/...check does not exist", + "Nodes can be restored manually(as in this command) but also automatically", + "", + "Automatic restore is done using the 'autorestore' attribute.", + "Once the node containing the 'autorestore' completes, the attribute is applied", + "", + " suite s", + " family farchive_now", + " autoarchive 0 # archive immediately after complete", + " task tx", + " endfamily", + " family frestore_from_task", + " task t1", + " trigger ../farchive_nowarchived", + " autorestore ../farchive_now # call autorestore when t1 completes", + " endfamily", + " endsuite", + "", + "In this example task '/s/frestore_from_task/t1' is only triggered if 'farchive_now'", + "is archived, then when t1 completes it will restore family 'farchive_now'", + "Usage::", + " --restore=/s1/f1 # restore family /s1/f1", + " --restore=/s1 /s2 # restore suites /s1 and /s2" ] }, { @@ -742,7 +1495,9 @@ "implementation": "CtsCmd", "summary": "Ask the server to load the definition from an check pt file.", "description": [ - "Ask the server to load the definition from an check pt file.\nThe server must be halted and the definition in the server must be deleted\nfirst, otherwise an error is returned" + "Ask the server to load the definition from an check pt file.", + "The server must be halted and the definition in the server must be deleted", + "first, otherwise an error is returned" ] }, { @@ -752,7 +1507,11 @@ "implementation": "PathsCmd", "summary": "Resume the given node. This allows job generation for the given node, or any child node.", "description": [ - "Resume the given node. This allows job generation for the given node, or any child node.\nUsage::\n --resume=/s1/f1/t1 # resume task s1/f1/t1\n --resume=/s1 /s2 # resume suites /s1 and /s2\n" + "Resume the given node. This allows job generation for the given node, or any child node.", + "Usage::", + " --resume=/s1/f1/t1 # resume task s1/f1/t1", + " --resume=/s1 /s2 # resume suites /s1 and /s2", + "" ] }, { @@ -762,7 +1521,29 @@ "implementation": "RunNodeCmd", "summary": "Ignore triggers, limits, time or date dependencies, just run the Task.", "description": [ - "Ignore triggers, limits, time or date dependencies, just run the Task.\nWhen a job completes, it may be automatically re-queued if it has a cron\nor multiple time dependencies. If we have multiple time based attributes,\nthen each run, will expire the time.\nWhen we run before the time, we want to avoid re-running the task then\na flag is set, so that it is not automatically re-queued.\nA repeat attribute is incremented when all the child nodes are complete\nin this case the child nodes are automatically re-queued.\nHence this command can be aid, in allowing a Repeat attribute to be incremented\n arg1 = (optional)force\n Forcibly run, even if there are nodes that are active or submitted\n This can result in zombie creation\n arg2 = node path(s). The paths must begin with a leading '/' character.\n If the path is /suite/family will recursively run all tasks\n When providing multiple paths avoid running the same task twice\nExample:\n --run=/suite/t1 # run task t1\nEffect:\n task t1; time 12:00 # will complete if run manually\n task t2; time 10:00 13:00 01:00 # will run 4 times before completing\n When we have a time range(i.e as shown with task t2), then next time slot\n is incremented for each run, until it expires, and the task completes.\n Use the Why command, to show next run time (i.e. next time slot)" + "Ignore triggers, limits, time or date dependencies, just run the Task.", + "When a job completes, it may be automatically re-queued if it has a cron", + "or multiple time dependencies. If we have multiple time based attributes,", + "then each run, will expire the time.", + "When we run before the time, we want to avoid re-running the task then", + "a flag is set, so that it is not automatically re-queued.", + "A repeat attribute is incremented when all the child nodes are complete", + "in this case the child nodes are automatically re-queued.", + "Hence this command can be aid, in allowing a Repeat attribute to be incremented", + " arg1 = (optional)force", + " Forcibly run, even if there are nodes that are active or submitted", + " This can result in zombie creation", + " arg2 = node path(s). The paths must begin with a leading '/' character.", + " If the path is /suite/family will recursively run all tasks", + " When providing multiple paths avoid running the same task twice", + "Example:", + " --run=/suite/t1 # run task t1", + "Effect:", + " task t1; time 12:00 # will complete if run manually", + " task t2; time 10:00 13:00 01:00 # will run 4 times before completing", + " When we have a time range(i.e as shown with task t2), then next time slot", + " is incremented for each run, until it expires, and the task completes.", + " Use the Why command, to show next run time (i.e. next time slot)" ] }, { @@ -772,13 +1553,37 @@ "implementation": "CtsCmd", "summary": "Generates gnuplot files that show the server load graphically.", "description": [ - "Generates gnuplot files that show the server load graphically.\nThis is done by parsing the log file. If no log file is provided,\nthen the log file path is obtained from the server. If the returned\nlog file path is not accessible an error is returned\nThis command produces a three files in the CWD.\n o ..gnuplot.dat\n o ..gnuplot.script\n o ..png", - "The generated script can be manually changed, to see different rendering\neffects. i.e. just run 'gnuplot ..gnuplot.script'", + "Generates gnuplot files that show the server load graphically.", + "This is done by parsing the log file. If no log file is provided,", + "then the log file path is obtained from the server. If the returned", + "log file path is not accessible an error is returned", + "This command produces a three files in the CWD.", + " o ..gnuplot.dat", + " o ..gnuplot.script", + " o ..png", + "", + "The generated script can be manually changed, to see different rendering", + "effects. i.e. just run 'gnuplot ..gnuplot.script'", + "", " arg1 = path to log file", - "If the path to log file is known, it is *preferable* to use this,\nrather than requesting the log path from the server.", - "Usage:\n --server_load=/path/to_log_file # Parses log and generate gnuplot files\n --server_load # Log file path is requested from server\n # which is then used to generate gnuplot files\n # *AVOID* if log file path is accessible", + "", + "If the path to log file is known, it is *preferable* to use this,", + "rather than requesting the log path from the server.", + "", + "Usage:", + " --server_load=/path/to_log_file # Parses log and generate gnuplot files", + " --server_load # Log file path is requested from server", + " # which is then used to generate gnuplot files", + " # *AVOID* if log file path is accessible", + "", "Now use any png viewer to see the output i.e", - "> display ..png\n> feh ..png\n> eog ..png\n> xdg-open ..png\n> w3m ..png\n" + "", + "> display ..png", + "> feh ..png", + "> eog ..png", + "> xdg-open ..png", + "> w3m ..png", + "" ] }, { @@ -788,7 +1593,11 @@ "implementation": "ServerVersionCmd", "summary": "Returns the version number of the server", "description": [ - "Returns the version number of the server\nUsage:\n --server_version\n Writes the version to standard output\n" + "Returns the version number of the server", + "Usage:", + " --server_version", + " Writes the version to standard output", + "" ] }, { @@ -798,9 +1607,39 @@ "implementation": "ShowCmd", "summary": "Used to print state of the definition returned from the server to standard output.", "description": [ - "Used to print state of the definition returned from the server to standard output.\nThis command can *only* be used in a group command, and will only work if it is\npreceded with a get command. See examples below.\n arg1 = [ defs | state | migrate ] \nThe output of show has several options: i.e\n o no arguments: With no arguments, print the definition structure to standard output\n Extern's are automatically added, allowing the output to be reloaded into the server\n i.e --group=\"get ; show\"\n o state:\n This will output definition structure along with all the state information.\n This will include the trigger expressions, abstract syntax tree as comments.\n Excludes the edit history\n o migrate:\n This will output definition structure along with all the state information.\n The node state is shown in the comments.\n This format allows the definition to be migrated to future version of ecflow.\n The output includes edit history but excludes externs.\n When the definition is reloaded *NO* checking is done.", - "The following shows a summary of the features associated with each choice\n DEFS STATE MIGRATE\nAuto generate externs Yes Yes No\nChecking on reload Yes Yes No\nEdit History No No Yes\ntrigger AST No Yes No", - "Usage:\n --group=\"get ; show\"\n --group=\"get ; show defs\" # same as the previous example\n --group=\"get ; show state\" # Show all state for the node tree\n --group=\"get ; show migrate\" # Shows state and allows migration\n --group=\"get=/s1; show\" # show state for the node only\n --group=\"get=/s1; show state\"" + "Used to print state of the definition returned from the server to standard output.", + "This command can *only* be used in a group command, and will only work if it is", + "preceded with a get command. See examples below.", + " arg1 = [ defs | state | migrate ] ", + "The output of show has several options: i.e", + " o no arguments: With no arguments, print the definition structure to standard output", + " Extern's are automatically added, allowing the output to be reloaded into the server", + " i.e --group=\"get ; show\"", + " o state:", + " This will output definition structure along with all the state information.", + " This will include the trigger expressions, abstract syntax tree as comments.", + " Excludes the edit history", + " o migrate:", + " This will output definition structure along with all the state information.", + " The node state is shown in the comments.", + " This format allows the definition to be migrated to future version of ecflow.", + " The output includes edit history but excludes externs.", + " When the definition is reloaded *NO* checking is done.", + "", + "The following shows a summary of the features associated with each choice", + " DEFS STATE MIGRATE", + "Auto generate externs Yes Yes No", + "Checking on reload Yes Yes No", + "Edit History No No Yes", + "trigger AST No Yes No", + "", + "Usage:", + " --group=\"get ; show\"", + " --group=\"get ; show defs\" # same as the previous example", + " --group=\"get ; show state\" # Show all state for the node tree", + " --group=\"get ; show migrate\" # Shows state and allows migration", + " --group=\"get=/s1; show\" # show state for the node only", + " --group=\"get=/s1; show state\"" ] }, { @@ -810,7 +1649,17 @@ "implementation": "CtsCmd", "summary": "Stop server from scheduling new jobs.", "description": [ - "Stop server from scheduling new jobs.\n arg1 = yes(optional) # use to bypass confirmation prompt,i.e\n --shutdown=yes\nThe following table shows server behaviour in the different states.\n|----------------------------------------------------------------------------------|\n| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |\n|--------------|--------------|--------------|---------------|---------------------|\n| RUNNING | yes | yes | yes | yes |\n| SHUTDOWN | yes | yes | no | yes |\n| HALTED | yes | no | no | no |\n|--------------|--------------|--------------|---------------|---------------------|" + "Stop server from scheduling new jobs.", + " arg1 = yes(optional) # use to bypass confirmation prompt,i.e", + " --shutdown=yes", + "The following table shows server behaviour in the different states.", + "|----------------------------------------------------------------------------------|", + "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |", + "|--------------|--------------|--------------|---------------|---------------------|", + "| RUNNING | yes | yes | yes | yes |", + "| SHUTDOWN | yes | yes | no | yes |", + "| HALTED | yes | no | no | no |", + "|--------------|--------------|--------------|---------------|---------------------|" ] }, { @@ -844,7 +1693,23 @@ "implementation": "PathsCmd", "summary": "Shows the status of a job associated with a task, in %ECF_JOB%.stat file", "description": [ - "Shows the status of a job associated with a task, in %ECF_JOB%.stat file\nIf a family or suite is selected, will invoke status command hierarchically.\nStatus uses the ECF_STATUS_CMD variable. After variable substitution it is invoked as a command.\nThe command should be written in such a way that the output is written to %ECF_JOB%.stat\nThis will allow the output of status command to be shown by the --file command\ni.e /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1::\nIf the process id cannot be found on the remote system, then the status command can also\narrange for the task to be aborted\nThe status command can fail for the following reasons:\n - ECF_STATUS_CMD not found\n - variable substitution fails\n - state is active but it can't find process id, i.e. ECF_RID\n - the status command does not exit cleanly\nWhen this happens a flag is set, STATUSCMD_FAILED, which is visible in the GUI\nUsage::\n --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat\n --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" + "Shows the status of a job associated with a task, in %ECF_JOB%.stat file", + "If a family or suite is selected, will invoke status command hierarchically.", + "Status uses the ECF_STATUS_CMD variable. After variable substitution it is invoked as a command.", + "The command should be written in such a way that the output is written to %ECF_JOB%.stat", + "This will allow the output of status command to be shown by the --file command", + "i.e /home/ma/emos/bin/ecfstatus %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.stat 2>&1::", + "If the process id cannot be found on the remote system, then the status command can also", + "arrange for the task to be aborted", + "The status command can fail for the following reasons:", + " - ECF_STATUS_CMD not found", + " - variable substitution fails", + " - state is active but it can't find process id, i.e. ECF_RID", + " - the status command does not exit cleanly", + "When this happens a flag is set, STATUSCMD_FAILED, which is visible in the GUI", + "Usage::", + " --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat", + " --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" ] }, { @@ -862,7 +1727,11 @@ "implementation": "PathsCmd", "summary": "Suspend the given node. This prevents job generation for the given node, or any child node.", "description": [ - "Suspend the given node. This prevents job generation for the given node, or any child node.\nUsage::\n --suspend=/s1/f1/t1 # suspend task s1/f1/t1\n --suspend=/s1 /s2 # suspend suites /s1 and /s2\n" + "Suspend the given node. This prevents job generation for the given node, or any child node.", + "Usage::", + " --suspend=/s1/f1/t1 # suspend task s1/f1/t1", + " --suspend=/s1 /s2 # suspend suites /s1 and /s2", + "" ] }, { @@ -872,7 +1741,12 @@ "implementation": "CSyncCmd", "summary": "Incrementally synchronise the local definition with the one in the server.", "description": [ - "Incrementally synchronise the local definition with the one in the server.\n*Important* for use with c++/python interface only.\nPreference should be given to this method as only the changes are returned.\nThis reduces the network bandwidth required to keep in sync with the server\nRequires a client handle, change and modify number, to get the incremental changes from server.\nThe change in server state is then and merged with the client definition." + "Incrementally synchronise the local definition with the one in the server.", + "*Important* for use with c++/python interface only.", + "Preference should be given to this method as only the changes are returned.", + "This reduces the network bandwidth required to keep in sync with the server", + "Requires a client handle, change and modify number, to get the incremental changes from server.", + "The change in server state is then and merged with the client definition." ] }, { @@ -882,7 +1756,13 @@ "implementation": "CSyncCmd", "summary": "Incrementally synchronise the local definition with the one in the server.", "description": [ - "Incrementally synchronise the local definition with the one in the server.\n*Important* for use with c++/python interface only.\nSame as sync, but will *always* sync with suite clock if it has changed.\nPreference should be given to this method as only the changes are returned.\nThis reduces the network bandwidth required to keep in sync with the server\nRequires a client handle, change and modify number, to get the incremental changes from server.\nThe change in server state is then and merged with the client definition." + "Incrementally synchronise the local definition with the one in the server.", + "*Important* for use with c++/python interface only.", + "Same as sync, but will *always* sync with suite clock if it has changed.", + "Preference should be given to this method as only the changes are returned.", + "This reduces the network bandwidth required to keep in sync with the server", + "Requires a client handle, change and modify number, to get the incremental changes from server.", + "The change in server state is then and merged with the client definition." ] }, { @@ -892,7 +1772,9 @@ "implementation": "CSyncCmd", "summary": "Returns the full definition from the server.", "description": [ - "Returns the full definition from the server.\n*Important* for use with c++/python interface only.\nRequires a client_handle. The returned definition is stored on the client." + "Returns the full definition from the server.", + "*Important* for use with c++/python interface only.", + "Requires a client_handle. The returned definition is stored on the client." ] }, { @@ -902,7 +1784,9 @@ "implementation": "CtsCmd", "summary": "Terminate the server.", "description": [ - "Terminate the server.\n arg1 = yes(optional) # use to bypass confirmation prompt.i.e\n --terminate=yes" + "Terminate the server.", + " arg1 = yes(optional) # use to bypass confirmation prompt.i.e", + " --terminate=yes" ] }, { @@ -912,8 +1796,12 @@ "implementation": "CtsWaitCmd", "summary": "Evaluates an expression, and block while the expression is false.", "description": [ - "Evaluates an expression, and block while the expression is false.\nFor use in the '.ecf' file *only*, hence the context is supplied via environment variables\n arg1 = string(expression)", - "Usage:\n ecflow_client --wait=\"/suite/taskx == complete\"" + "Evaluates an expression, and block while the expression is false.", + "For use in the '.ecf' file *only*, hence the context is supplied via environment variables", + " arg1 = string(expression)", + "", + "Usage:", + " ecflow_client --wait=\"/suite/taskx == complete\"" ], "arguments": [ { @@ -931,7 +1819,16 @@ "implementation": "CtsNodeCmd", "summary": "Show the reason why a node is not running.", "description": [ - "Show the reason why a node is not running.\nCan only be used with the group command. The group command must include a \n'get' command(i.e returns the server defs)\nThe why command take a optional string argument representing a node path\nWill return reason why the node is holding and for all its children.\nIf no arguments supplied will report on all nodes\n arg = node path | arg = NULL\nUsage:\n --group=\"get; why\" # returns why for all holding nodes\n --group=\"get; why=/suite/family\" # returns why for a specific node" + "Show the reason why a node is not running.", + "Can only be used with the group command. The group command must include a ", + "'get' command(i.e returns the server defs)", + "The why command take a optional string argument representing a node path", + "Will return reason why the node is holding and for all its children.", + "If no arguments supplied will report on all nodes", + " arg = node path | arg = NULL", + "Usage:", + " --group=\"get; why\" # returns why for all holding nodes", + " --group=\"get; why=/suite/family\" # returns why for a specific node" ] }, { @@ -941,7 +1838,8 @@ "implementation": "CtsCmd", "summary": "Returns the list of zombies from the server.", "description": [ - "Returns the list of zombies from the server.\nResults reported to standard output." + "Returns the list of zombies from the server.", + "Results reported to standard output." ] }, { @@ -951,7 +1849,12 @@ "implementation": "ZombieCmd", "summary": "Locates the task in the servers list of zombies, and sets to adopt.", "description": [ - "Locates the task in the servers list of zombies, and sets to adopt.\nNext time a child command (init,event,meter,label,abort,complete,wait queue) communicates with the server, the password on the zombie is adopted by the task.\nThis is only allowed if the process id matches, otherwise an error is issued.\nThe zombie reference stored in the server is then deleted.\n args = list of task paths, at least one expected\n --zombie_adopt=/path/to/task /path/to/task2" + "Locates the task in the servers list of zombies, and sets to adopt.", + "Next time a child command (init,event,meter,label,abort,complete,wait queue) communicates with the server, the password on the zombie is adopted by the task.", + "This is only allowed if the process id matches, otherwise an error is issued.", + "The zombie reference stored in the server is then deleted.", + " args = list of task paths, at least one expected", + " --zombie_adopt=/path/to/task /path/to/task2" ] }, { @@ -961,7 +1864,13 @@ "implementation": "ZombieCmd", "summary": "Locates the task in the servers list of zombies, and sets flags to block it.", "description": [ - "Locates the task in the servers list of zombies, and sets flags to block it.\nThis is default behaviour of the child commands(init,abort,complete,wait,queue)\nwhen the server cannot match the passwords. Each child commands will continue\nattempting to connect to the server for 24 hours, and will then return an error.\nThe connection timeout can be configured with environment ECF_TIMEOUT\n args = list of task paths, at least one expected\n --zombie_block=/path/to/task /path/to/task2" + "Locates the task in the servers list of zombies, and sets flags to block it.", + "This is default behaviour of the child commands(init,abort,complete,wait,queue)", + "when the server cannot match the passwords. Each child commands will continue", + "attempting to connect to the server for 24 hours, and will then return an error.", + "The connection timeout can be configured with environment ECF_TIMEOUT", + " args = list of task paths, at least one expected", + " --zombie_block=/path/to/task /path/to/task2" ] }, { @@ -971,7 +1880,14 @@ "implementation": "ZombieCmd", "summary": "Locates the task in the servers list of zombies, and sets to fail.", "description": [ - "Locates the task in the servers list of zombies, and sets to fail.\nNext time a child command (init,event,meter,label,abort,complete) which matches zombie, communicates with the server, will be set to fail.\nDepending on the job setup this may force a abort, the abort will also fail.\nHence job structure should use 'set -e' in the error trapping functions to prevent\ninfinite recursion.\nThe references to the zombie in the server is automatically deleted after 1 hour\n args = list of task paths, at least one expected\n --zombie_fail=/path/to/task /path/to/task2" + "Locates the task in the servers list of zombies, and sets to fail.", + "Next time a child command (init,event,meter,label,abort,complete) which matches zombie, communicates with the server, will be set to fail.", + "Depending on the job setup this may force a abort, the abort will also fail.", + "Hence job structure should use 'set -e' in the error trapping functions to prevent", + "infinite recursion.", + "The references to the zombie in the server is automatically deleted after 1 hour", + " args = list of task paths, at least one expected", + " --zombie_fail=/path/to/task /path/to/task2" ] }, { @@ -981,7 +1897,14 @@ "implementation": "ZombieCmd", "summary": "Locates the task in the servers list of zombies, and sets to fob.", "description": [ - "Locates the task in the servers list of zombies, and sets to fob.\nThis default behaviour of the child commands(label,event,meter) is to fob\nNext time the child commands (init,event,meter,label,abort,complete,wait,queue) communicate\nwith the server, they will complete successfully (but without updating the node tree)\nallowing the job to finish.\nThe references to the zombie in the server is automatically deleted after 1 hour\n args = list of task paths, at least one expected\n --zombie_fob=/path/to/task1 /path/to/task2" + "Locates the task in the servers list of zombies, and sets to fob.", + "This default behaviour of the child commands(label,event,meter) is to fob", + "Next time the child commands (init,event,meter,label,abort,complete,wait,queue) communicate", + "with the server, they will complete successfully (but without updating the node tree)", + "allowing the job to finish.", + "The references to the zombie in the server is automatically deleted after 1 hour", + " args = list of task paths, at least one expected", + " --zombie_fob=/path/to/task1 /path/to/task2" ] }, { @@ -991,7 +1914,13 @@ "implementation": "ZombieCmd", "summary": "Locates the task in the servers list of zombies, and sets flags to kill", "description": [ - "Locates the task in the servers list of zombies, and sets flags to kill\nThe kill is done using ECF_KILL_CMD, but using the process_id from the zombie\nThe job is allowed to continue until the kill is received\nCan only kill zombies that have an associated Task, hence path zombies\nmust be killed manually.\n arg = list of task paths, at least one expected\n --zombie_kill=/path/to/task /path/to/task2" + "Locates the task in the servers list of zombies, and sets flags to kill", + "The kill is done using ECF_KILL_CMD, but using the process_id from the zombie", + "The job is allowed to continue until the kill is received", + "Can only kill zombies that have an associated Task, hence path zombies", + "must be killed manually.", + " arg = list of task paths, at least one expected", + " --zombie_kill=/path/to/task /path/to/task2" ] }, { @@ -1001,7 +1930,11 @@ "implementation": "ZombieCmd", "summary": "Locates the task in the servers list of zombies, and removes it.", "description": [ - "Locates the task in the servers list of zombies, and removes it.\nSince a job typically has many child commands (i.e init, complete, event, meter, label, wait, queue)\nthe zombie may reappear\n args = list of task paths, at least one expected\n --zombie_remove=/path/to/task /path/to/task2" + "Locates the task in the servers list of zombies, and removes it.", + "Since a job typically has many child commands (i.e init, complete, event, meter, label, wait, queue)", + "the zombie may reappear", + " args = list of task paths, at least one expected", + " --zombie_remove=/path/to/task /path/to/task2" ] } ], @@ -1010,43 +1943,33 @@ "name": "host", "kind": "global-option", "summary": "When specified overrides the environment variable ECF_HOST and default host: 'localhost'", - "description": [ - "When specified overrides the environment variable ECF_HOST and default host: 'localhost'" - ] + "description": ["When specified overrides the environment variable ECF_HOST and default host: 'localhost'"] }, { "name": "port", "kind": "global-option", "summary": "When specified overrides the environment variable ECF_PORT and default port: '3141'", - "description": [ - "When specified overrides the environment variable ECF_PORT and default port: '3141'" - ] + "description": ["When specified overrides the environment variable ECF_PORT and default port: '3141'"] }, { "name": "user", "kind": "global-option", "summary": "Specifies the user name used to contact the server. Must be used in combination with option --password.", - "description": [ - "Specifies the user name used to contact the server. Must be used in combination with option --password." - ], + "description": ["Specifies the user name used to contact the server. Must be used in combination with option --password."], "pairs_with": "password" }, { "name": "password", "kind": "global-option", "summary": "Specifies the password used to contact the server. Must be used in combination with option --user.", - "description": [ - "Specifies the password used to contact the server. Must be used in combination with option --user." - ], + "description": ["Specifies the password used to contact the server. Must be used in combination with option --user."], "pairs_with": "user" }, { "name": "rid", "kind": "global-option", "summary": "When specified overrides the environment variable ECF_RID. Can only be used for task commands.", - "description": [ - "When specified overrides the environment variable ECF_RID. Can only be used for task commands." - ] + "description": ["When specified overrides the environment variable ECF_RID. Can only be used for task commands."] }, { "name": "ssl", @@ -1054,7 +1977,8 @@ "requires": "ECF_OPENSSL", "summary": "Enables the use of SSL when contacting the server.", "description": [ - "Enables the use of SSL when contacting the server.\nWhen specified overrides the environment variable ECF_SSL." + "Enables the use of SSL when contacting the server.", + "When specified overrides the environment variable ECF_SSL." ] }, { @@ -1062,7 +1986,8 @@ "kind": "global-option", "summary": "Enables communication over HTTP between client/server.", "description": [ - "Enables communication over HTTP between client/server.\n" + "Enables communication over HTTP between client/server.", + "" ] }, { @@ -1070,31 +1995,29 @@ "kind": "global-option", "summary": "Enables communication over HTTPS between client/server.", "description": [ - "Enables communication over HTTPS between client/server.\n" + "Enables communication over HTTPS between client/server.", + "" ] }, { "name": "help", "kind": "global-option", "summary": "Produce help message", - "description": [ - "Produce help message" - ] + "description": ["Produce help message"] }, { "name": "version", "kind": "global-option", "summary": "Show ecflow client version number, and version of the boost library used", - "description": [ - "Show ecflow client version number, and version of the boost library used" - ] + "description": ["Show ecflow client version number, and version of the boost library used"] }, { "name": "debug", "kind": "global-option", "summary": "Enables the display of client environment settings and execution details.", "description": [ - "Enables the display of client environment settings and execution details.\nHas the same effect as setting environment variable ECF_DEBUG_CLIENT." + "Enables the display of client environment settings and execution details.", + "Has the same effect as setting environment variable ECF_DEBUG_CLIENT." ] }, { @@ -1102,9 +2025,7 @@ "kind": "command-option", "command": "init", "summary": "Add variables e.g. name1=value1 name2=value2. Can only be used in combination with --init command.", - "description": [ - "Add variables e.g. name1=value1 name2=value2. Can only be used in combination with --init command." - ] + "description": ["Add variables e.g. name1=value1 name2=value2. Can only be used in combination with --init command."] }, { "name": "remove", diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index f8baceb71..4d4936edb 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -28,14 +28,13 @@ } }, "$defs": { - "description_block": { - "description": "A paragraph of prose. Joined with the next block by a blank line; this reproduces preformatted content (e.g. CtsCmd's ASCII-art tables) byte-for-byte too, since any blank lines within such a block round-trip through the same join, without needing a distinct verbatim representation.", - "type": "string", - "minLength": 1 + "description_line": { + "description": "A single line of the help text, with no embedded newline. The lines are joined with a newline to reconstruct the original text verbatim (including preformatted content, e.g. CtsCmd's ASCII-art tables); a blank line in the source is represented as an empty string, so an empty string is allowed.", + "type": "string" }, "description": { "type": "array", - "items": { "$ref": "#/$defs/description_block" } + "items": { "$ref": "#/$defs/description_line" } }, "argument": { "description": "Structured, best-effort metadata alongside the verbatim argN prose kept in the command's own description; the source's argN convention is inconsistent per-command (some omit type, some omit a separate description line, one uses a union type), so type and description are not always present, and type is free text rather than a closed set.", diff --git a/docs/client_api/validate_help_manifest.py b/docs/client_api/validate_help_manifest.py index 6b0fb20af..fc7d1605a 100755 --- a/docs/client_api/validate_help_manifest.py +++ b/docs/client_api/validate_help_manifest.py @@ -81,6 +81,13 @@ def check_cross_references(manifest): f"environment variable '{variable['name']}' overridable_by unknown global-option '{overridable_by}'" ) + # A description holds one line per array element; no element may contain an embedded newline. + for kind, entries in (("command", manifest.get("commands", [])), ("option", manifest.get("options", []))): + for entry in entries: + for index, line in enumerate(entry.get("description", [])): + if "\n" in line: + problems.append(f"{kind} '{entry['name']}' description line {index} contains an embedded newline") + return problems diff --git a/libs/base/src/ecflow/base/HelpCatalog.cpp b/libs/base/src/ecflow/base/HelpCatalog.cpp index e7157ef89..c598be904 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.cpp +++ b/libs/base/src/ecflow/base/HelpCatalog.cpp @@ -47,11 +47,13 @@ std::optional HelpCatalog::description_for(const std::string& name) } std::string text; - for (const auto& block : entry->at("description")) { - if (!text.empty()) { - text += "\n\n"; + bool first = true; + for (const auto& line : entry->at("description")) { + if (!first) { + text += "\n"; } - text += block.get(); + first = false; + text += line.get(); } return text; } diff --git a/libs/base/src/ecflow/base/HelpCatalog.hpp b/libs/base/src/ecflow/base/HelpCatalog.hpp index 9687567f3..110b33996 100644 --- a/libs/base/src/ecflow/base/HelpCatalog.hpp +++ b/libs/base/src/ecflow/base/HelpCatalog.hpp @@ -87,9 +87,10 @@ class HelpCatalog { /// @brief Returns the full description text registered for a command or option. /// /// Checks commands first, then options, matching @ref find_command and - /// @ref find_option order. The entry's "description" blocks are joined the - /// same way the paragraphs were originally separated in the C++ source: a - /// blank line between blocks. This reproduces preformatted content as is. + /// @ref find_option order. The entry's "description" array holds one line + /// per element (a blank line is an empty string); the lines are joined with + /// a newline, reconstructing the original text verbatim, preformatted + /// content included. /// /// @param name Exact command or option name to look up, e.g. "abort". /// @return The reconstructed description text, or std::nullopt if @p name diff --git a/libs/base/test/TestHelpCatalog.cpp b/libs/base/test/TestHelpCatalog.cpp index e630f89bd..a86447cdb 100644 --- a/libs/base/test/TestHelpCatalog.cpp +++ b/libs/base/test/TestHelpCatalog.cpp @@ -122,6 +122,32 @@ BOOST_AUTO_TEST_CASE(test_description_for_command_and_option) { BOOST_CHECK(!ecf::HelpCatalog::description_for("no-such-name").has_value()); } +BOOST_AUTO_TEST_CASE(test_description_for_joins_lines_with_newline) { + ECF_NAME_THIS_TEST(); + + // The description holds one line per array element; description_for() joins them with a single + // newline, so the reconstruction equals the elements joined by '\n', verbatim. + const nlohmann::json* entry = ecf::HelpCatalog::find_command("abort"); + BOOST_REQUIRE(entry != nullptr); + + std::string expected; + bool first = true; + for (const auto& line : entry->at("description")) { + if (!first) { + expected += "\n"; + } + first = false; + expected += line.get(); + } + + std::optional actual = ecf::HelpCatalog::description_for("abort"); + BOOST_REQUIRE(actual.has_value()); + BOOST_CHECK_EQUAL(*actual, expected); + + // A blank line between paragraphs is stored as an empty element and reappears as "\n\n". + BOOST_CHECK(actual->find("\n\n") != std::string::npos); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() From 28f4f50a32b5ac3bbf19019f17db7c26413e57d1 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 06:21:22 +0100 Subject: [PATCH 45/49] Normalise Usage heading spacing in the help manifest Every command help entry now has one blank line before and after the "Usage:" heading, and all heading variants (notably "Usage::") are canonicalised to "Usage:". Documentation was regenerated to match. --- docs/client_api/api/abort.rst | 1 + docs/client_api/api/archive.rst | 3 +- docs/client_api/api/begin.rst | 2 + docs/client_api/api/ch_add.rst | 2 + docs/client_api/api/ch_auto_add.rst | 2 + docs/client_api/api/ch_drop.rst | 2 + docs/client_api/api/ch_drop_user.rst | 2 + docs/client_api/api/ch_register.rst | 2 + docs/client_api/api/ch_rem.rst | 2 + docs/client_api/api/check.rst | 2 + docs/client_api/api/check_pt.rst | 2 + docs/client_api/api/complete.rst | 1 + docs/client_api/api/delete.rst | 2 + docs/client_api/api/edit_history.rst | 4 +- docs/client_api/api/edit_script.rst | 2 + docs/client_api/api/event.rst | 1 + docs/client_api/api/force.rst | 2 + docs/client_api/api/free-dep.rst | 2 + docs/client_api/api/get.rst | 2 + docs/client_api/api/get_state.rst | 2 + docs/client_api/api/group.rst | 2 + docs/client_api/api/init.rst | 1 + docs/client_api/api/kill.rst | 4 +- docs/client_api/api/label.rst | 1 + docs/client_api/api/load.rst | 2 + docs/client_api/api/log.rst | 2 + docs/client_api/api/meter.rst | 1 + docs/client_api/api/migrate.rst | 1 + docs/client_api/api/msg.rst | 2 + docs/client_api/api/order.rst | 2 + docs/client_api/api/ping.rst | 2 + docs/client_api/api/plug.rst | 2 + docs/client_api/api/query.rst | 1 + docs/client_api/api/queue.rst | 1 + .../client_api/api/reloadcustompasswdfile.rst | 1 + docs/client_api/api/reloadpasswdfile.rst | 1 + docs/client_api/api/reloadwsfile.rst | 2 +- docs/client_api/api/replace.rst | 1 + docs/client_api/api/requeue.rst | 1 + docs/client_api/api/restore.rst | 4 +- docs/client_api/api/resume.rst | 4 +- docs/client_api/api/server_load.rst | 1 + docs/client_api/api/server_version.rst | 2 + docs/client_api/api/show.rst | 1 + docs/client_api/api/status.rst | 4 +- docs/client_api/api/suspend.rst | 4 +- docs/client_api/api/wait.rst | 1 + docs/client_api/api/why.rst | 2 + docs/client_api/help.json | 93 +++++++++++++++++-- 49 files changed, 170 insertions(+), 16 deletions(-) diff --git a/docs/client_api/api/abort.rst b/docs/client_api/api/abort.rst index 577b6c0bd..dcf975499 100644 --- a/docs/client_api/api/abort.rst +++ b/docs/client_api/api/abort.rst @@ -31,6 +31,7 @@ The following help text is generated by :code:`ecflow_client --help=abort` Otherwise the blocking period is defined by ECF_TIMEOUT. Usage: + ecflow_client --abort=reasonX The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/archive.rst b/docs/client_api/api/archive.rst index e71c717c8..6fdf8c870 100644 --- a/docs/client_api/api/archive.rst +++ b/docs/client_api/api/archive.rst @@ -53,7 +53,8 @@ The following help text is generated by :code:`ecflow_client --help=archive` endfamily endsuite - Usage:: + Usage: + --archive=/s1 # archive suite s1 --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2 --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks diff --git a/docs/client_api/api/begin.rst b/docs/client_api/api/begin.rst index c96eac0a2..4de6a70b4 100644 --- a/docs/client_api/api/begin.rst +++ b/docs/client_api/api/begin.rst @@ -28,7 +28,9 @@ The following help text is generated by :code:`ecflow_client --help=begin` force means reset the begin status on the suites and bypass checks. This is only required if suite-name is provide as the first argument Using force can cause the creation of zombies + Usage: + --begin # will begin all suites --begin="--force" # reset and then begin all suites, bypassing any checks. Note: string must be quoted --begin="mySuite" # begin playing suite of name 'mySuite' diff --git a/docs/client_api/api/ch_add.rst b/docs/client_api/api/ch_add.rst index 9ae8d4a59..62fd19f9e 100644 --- a/docs/client_api/api/ch_add.rst +++ b/docs/client_api/api/ch_add.rst @@ -24,7 +24,9 @@ The following help text is generated by :code:`ecflow_client --help=ch_add` Add a set of suites, to an existing handle. arg1 = handle(integer) # The handle must be an integer that is > 0 arg2 = names # should be a list of suite names, names not in the definition are ignored + Usage: + --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10 An error is returned if the handle had not previously been registered The handle is created with --ch_register command diff --git a/docs/client_api/api/ch_auto_add.rst b/docs/client_api/api/ch_auto_add.rst index 8082bae2b..b0ccee893 100644 --- a/docs/client_api/api/ch_auto_add.rst +++ b/docs/client_api/api/ch_auto_add.rst @@ -24,7 +24,9 @@ The following help text is generated by :code:`ecflow_client --help=ch_auto_add` Change an existing handle so that new suites can be added automatically. arg1 = handle(integer) # The handle must be an integer that is > 0 arg2 = true | false # true means add new suites to my list, when they are created + Usage: + --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it --ch_auto_add=10 false # modify handle 10 so that no new suites are added The handle is created with --ch_register command diff --git a/docs/client_api/api/ch_drop.rst b/docs/client_api/api/ch_drop.rst index b4e4e7e35..a23bcc7c8 100644 --- a/docs/client_api/api/ch_drop.rst +++ b/docs/client_api/api/ch_drop.rst @@ -24,7 +24,9 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop` Drop/de-register the client handle. Un-used handle should be dropped otherwise they will stay, in the server. arg1 = handle(integer) # The handle must be an integer that is > 0 + Usage: + --ch_drop=10 # drop the client handle 10 An error is returned if the handle had not previously been registered The handle stored on the local client is set to zero diff --git a/docs/client_api/api/ch_drop_user.rst b/docs/client_api/api/ch_drop_user.rst index 93469c035..c29e9b8bd 100644 --- a/docs/client_api/api/ch_drop_user.rst +++ b/docs/client_api/api/ch_drop_user.rst @@ -25,7 +25,9 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop_user If no user provided will drop for current user. Client must ensure un-used handle are dropped otherwise they will stay, in the server. arg1 = user # The user to be drooped, if left empty drop current user + Usage: + --ch_drop_user=ma0 # drop all handles associated with user ma0 --ch_drop_user # drop all handles associated with current user An error is returned if no registered handles diff --git a/docs/client_api/api/ch_register.rst b/docs/client_api/api/ch_register.rst index a0eda12df..c0360cef4 100644 --- a/docs/client_api/api/ch_register.rst +++ b/docs/client_api/api/ch_register.rst @@ -31,7 +31,9 @@ The following help text is generated by :code:`ecflow_client --help=ch_register` This command affects news() and sync() commands arg1 = true | false # true means add new suites to my list, when they are created arg2 = names # should be a list of suite names, names not in the definition are ignored + Usage: + --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only --ch_register=false # register handle, suites will be added later on diff --git a/docs/client_api/api/ch_rem.rst b/docs/client_api/api/ch_rem.rst index 9588a87bd..363d9eec2 100644 --- a/docs/client_api/api/ch_rem.rst +++ b/docs/client_api/api/ch_rem.rst @@ -24,7 +24,9 @@ The following help text is generated by :code:`ecflow_client --help=ch_rem` Remove a set of suites, from an existing handle. arg1 = handle(integer) # The handle must be an integer that is > 0 arg2 = names # should be a list of suite names, names not in the definition are ignored + Usage: + --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10 The handle is created with --ch_register command To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/check.rst b/docs/client_api/api/check.rst index 51c088777..a8a60eccb 100644 --- a/docs/client_api/api/check.rst +++ b/docs/client_api/api/check.rst @@ -26,7 +26,9 @@ The following help text is generated by :code:`ecflow_client --help=check` (Note: On the client side unresolved paths in trigger expressions must have an associated 'extern' specified) arg = [ _all_ | / | list of node paths ] + Usage: + --check=_all_ # Checks all the suites --check=/ # Checks all the suites --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1 diff --git a/docs/client_api/api/check_pt.rst b/docs/client_api/api/check_pt.rst index c3c80bebc..516f218e3 100644 --- a/docs/client_api/api/check_pt.rst +++ b/docs/client_api/api/check_pt.rst @@ -39,7 +39,9 @@ The following help text is generated by :code:`ecflow_client --help=check_pt` : This specifies the interval in seconds when server should automatically check pt. This will only take effect of mode is on_time/CHECK_ON_TIME Should ideally be a value greater than 60 seconds, default is 120 seconds + Usage: + --check_pt Immediately check point the definition held in the server --check_pt=never diff --git a/docs/client_api/api/complete.rst b/docs/client_api/api/complete.rst index 043aa0404..48c51998f 100644 --- a/docs/client_api/api/complete.rst +++ b/docs/client_api/api/complete.rst @@ -32,6 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=complete` arg1(--remove)(optional) = a list of variables to removed from this task Usage: + ecflow_client --complete ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task diff --git a/docs/client_api/api/delete.rst b/docs/client_api/api/delete.rst index 716e55507..74b7adb11 100644 --- a/docs/client_api/api/delete.rst +++ b/docs/client_api/api/delete.rst @@ -26,7 +26,9 @@ The following help text is generated by :code:`ecflow_client --help=delete` arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt arg3 = node paths | _all_ # _all_ means delete all suites # node paths must start with a leading '/' + Usage: + --delete=_all_ # Delete all suites in server. Use with care. --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted diff --git a/docs/client_api/api/edit_history.rst b/docs/client_api/api/edit_history.rst index 370c98af6..34553b0a7 100644 --- a/docs/client_api/api/edit_history.rst +++ b/docs/client_api/api/edit_history.rst @@ -23,7 +23,9 @@ The following help text is generated by :code:`ecflow_client --help=edit_history Returns the edit history associated with a Node. Can also be used to clear the edit history. - Usage:: + + Usage: + --edit_history=/s1/f1/t1 # return history of changes for the given node --edit_history=clear # clear/purge *ALL* edit history from all nodes. diff --git a/docs/client_api/api/edit_script.rst b/docs/client_api/api/edit_script.rst index 40ad08f51..780ab15bd 100644 --- a/docs/client_api/api/edit_script.rst +++ b/docs/client_api/api/edit_script.rst @@ -44,7 +44,9 @@ The following help text is generated by :code:`ecflow_client --help=edit_script` arg4 = create_alias (optional) default value is false, for use with 'submit_file' option arg5 = no_run (optional) default value is false, i.e immediately run the alias is no_run is specified the alias in only created + Usage: + --edit_script=/path/to/task edit > script_file server returns script with the used variables to standard out The user can choose to edit this file diff --git a/docs/client_api/api/event.rst b/docs/client_api/api/event.rst index dd74304ea..8ddc7907e 100644 --- a/docs/client_api/api/event.rst +++ b/docs/client_api/api/event.rst @@ -32,6 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=event` The default can be overridden by using zombie attributes. Usage: + ecflow_client --event=ev # set the event, default since event initial value is clear ecflow_client --event=ev set # set the event, explicit ecflow_client --event=ev clear # clear the event, use when event initial value is set diff --git a/docs/client_api/api/force.rst b/docs/client_api/api/force.rst index 0b70fac8a..a02f5cc37 100644 --- a/docs/client_api/api/force.rst +++ b/docs/client_api/api/force.rst @@ -36,7 +36,9 @@ The following help text is generated by :code:`ecflow_client --help=force` Set repeat variables to last value, only works in conjunction with recursive option arg4 = path_to_node or path_to_node:: paths must begin with '/' + Usage: + --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1 diff --git a/docs/client_api/api/free-dep.rst b/docs/client_api/api/free-dep.rst index 38e497fac..88ed3a810 100644 --- a/docs/client_api/api/free-dep.rst +++ b/docs/client_api/api/free-dep.rst @@ -32,7 +32,9 @@ The following help text is generated by :code:`ecflow_client --help=free-dep` arg4 = (optional) time Free all time dependencies i.e time, day, today, cron arg5 = List of paths. At least one required. Must start with a leading '/' + Usage: + --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2 --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1 --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1 diff --git a/docs/client_api/api/get.rst b/docs/client_api/api/get.rst index 52ca09fa2..ad54c5c48 100644 --- a/docs/client_api/api/get.rst +++ b/docs/client_api/api/get.rst @@ -52,7 +52,9 @@ The following help text is generated by :code:`ecflow_client --help=get` Get all suite node tree's from the server and write to standard out. The output is parse-able, and can be used to re-load the definition arg = NULL | arg = node path + Usage: + --get # gets the definition from the server,and writes to standard out --get=/s1 # gets the suite from the server,and writes to standard out diff --git a/docs/client_api/api/get_state.rst b/docs/client_api/api/get_state.rst index 1894a33f0..882c9c01d 100644 --- a/docs/client_api/api/get_state.rst +++ b/docs/client_api/api/get_state.rst @@ -25,7 +25,9 @@ The following help text is generated by :code:`ecflow_client --help=get_state` This will include event, meter, node state, trigger and time state. The output is written to standard out. arg = NULL | arg = node path + Usage: + --get_state # gets the definition from the server,and writes to standard out --get_state=/s1 # gets the suite from the server,and writes to standard out diff --git a/docs/client_api/api/group.rst b/docs/client_api/api/group.rst index 0589e47aa..e9c3cb478 100644 --- a/docs/client_api/api/group.rst +++ b/docs/client_api/api/group.rst @@ -25,7 +25,9 @@ The following help text is generated by :code:`ecflow_client --help=group` Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt provide 'yes' as an additional parameter. See example below. arg = string + Usage: + --group="halt=yes; reloadwsfile; restart;" # halt server,bypass the confirmation prompt, # reload white list file, restart server diff --git a/docs/client_api/api/init.rst b/docs/client_api/api/init.rst index c61d224f7..83a8713b6 100644 --- a/docs/client_api/api/init.rst +++ b/docs/client_api/api/init.rst @@ -32,6 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=init` Otherwise the blocking period is defined by ECF_TIMEOUT. Usage: + ecflow_client --init=$$ ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task diff --git a/docs/client_api/api/kill.rst b/docs/client_api/api/kill.rst index 9641cbdd2..0b24d6d5c 100644 --- a/docs/client_api/api/kill.rst +++ b/docs/client_api/api/kill.rst @@ -27,7 +27,9 @@ The following help text is generated by :code:`ecflow_client --help=kill` The command should be written in such a way that the output is written to %ECF_JOB%.kill as this allow the --file command to report the output: .e.e. /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1:: - Usage:: + + Usage: + --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2 --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1 diff --git a/docs/client_api/api/label.rst b/docs/client_api/api/label.rst index a12218bc2..d269df1ae 100644 --- a/docs/client_api/api/label.rst +++ b/docs/client_api/api/label.rst @@ -32,6 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=label` The default can be overridden by using zombie attributes. Usage: + ecflow_client --label=progressed merlin The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/load.rst b/docs/client_api/api/load.rst index fea5289fe..8072dda9d 100644 --- a/docs/client_api/api/load.rst +++ b/docs/client_api/api/load.rst @@ -30,7 +30,9 @@ The following help text is generated by :code:`ecflow_client --help=load` This command can also be used to load a checkpoint file into the server arg1 = path to the definition file or checkpoint file arg2 = (optional) [ force | check_only | print | stats ] # default = false for all + Usage: + --load=/my/home/exotic.def # will error if suites of same name exists --load=/my/home/exotic.def force # overwrite suite's of same name in the server --load=/my/home/exotic.def check_only # Just check, don't send to server diff --git a/docs/client_api/api/log.rst b/docs/client_api/api/log.rst index 2787fd034..30f2f9ce9 100644 --- a/docs/client_api/api/log.rst +++ b/docs/client_api/api/log.rst @@ -43,7 +43,9 @@ The following help text is generated by :code:`ecflow_client --help=log` arg2 = [ new_path | optional last n lines ] if get specified can specify lines to get. Value must be convertible to an integer Otherwise if arg1 is 'new' then the second argument must be a path + Usage: + --log=get # Write the last 100 lines of the log file to standard out --log=get 200 # Write the last 200 lines of the log file to standard out --log=clear # Clear the log file. The log is now empty diff --git a/docs/client_api/api/meter.rst b/docs/client_api/api/meter.rst index e46eaf606..3b0785dd6 100644 --- a/docs/client_api/api/meter.rst +++ b/docs/client_api/api/meter.rst @@ -31,6 +31,7 @@ The following help text is generated by :code:`ecflow_client --help=meter` The default can be overridden by using zombie attributes. Usage: + ecflow_client --meter=my_meter 20 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/migrate.rst b/docs/client_api/api/migrate.rst index 2f258f466..b72f561d9 100644 --- a/docs/client_api/api/migrate.rst +++ b/docs/client_api/api/migrate.rst @@ -36,6 +36,7 @@ The following help text is generated by :code:`ecflow_client --help=migrate` Show trigger AST No Yes No Usage: + --migrate # show all suites --migrate=/s1 # show state for suite s1 diff --git a/docs/client_api/api/msg.rst b/docs/client_api/api/msg.rst index cb39d32ea..84cc387ee 100644 --- a/docs/client_api/api/msg.rst +++ b/docs/client_api/api/msg.rst @@ -23,7 +23,9 @@ The following help text is generated by :code:`ecflow_client --help=msg` Writes the input string to the log file. arg1 = string + Usage: + --msg="place me in the log file" The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/order.rst b/docs/client_api/api/order.rst index 3bd617183..b57ddc3ff 100644 --- a/docs/client_api/api/order.rst +++ b/docs/client_api/api/order.rst @@ -42,7 +42,9 @@ The following help text is generated by :code:`ecflow_client --help=order` This command can fail because: - The node path does not exist in the server - The order_type is not does not match one of arg2 + Usage: + --order=/suite/f1 top # move node f1 to the top The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/ping.rst b/docs/client_api/api/ping.rst index a9c0e4bcf..661b62aee 100644 --- a/docs/client_api/api/ping.rst +++ b/docs/client_api/api/ping.rst @@ -22,7 +22,9 @@ The following help text is generated by :code:`ecflow_client --help=ping` ---- Check if server is running on given host/port. Result reported to standard output. + Usage: + --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144 --ping --host=fred # Check if server alive on host fred and port ECF_PORT, # otherwise default port of 3141 diff --git a/docs/client_api/api/plug.rst b/docs/client_api/api/plug.rst index de486b2f7..771ba253c 100644 --- a/docs/client_api/api/plug.rst +++ b/docs/client_api/api/plug.rst @@ -34,7 +34,9 @@ The following help text is generated by :code:`ecflow_client --help=plug` then the source node must correspond to a suite. - If the source node is added as a child, then its name must be unique amongst its peers + Usage: + --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141) The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/query.rst b/docs/client_api/api/query.rst index b9be43e39..362662316 100644 --- a/docs/client_api/api/query.rst +++ b/docs/client_api/api/query.rst @@ -153,6 +153,7 @@ The following help text is generated by :code:`ecflow_client --help=query` arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat Usage: + ecflow_client --query state / # return top level state to standard out ecflow_client --query state /path/to/node # return node state to standard out ecflow_client --query dstate /path/to/node # state that can included suspended diff --git a/docs/client_api/api/queue.rst b/docs/client_api/api/queue.rst index ace9981ee..0dd78d2f8 100644 --- a/docs/client_api/api/queue.rst +++ b/docs/client_api/api/queue.rst @@ -38,6 +38,7 @@ The following help text is generated by :code:`ecflow_client --help=queue` search for the queue up the node hierarchy. If no queue found, command fails Usage: + step="" QNAME="my_queue_name" while [1 == 1 ] ; do diff --git a/docs/client_api/api/reloadcustompasswdfile.rst b/docs/client_api/api/reloadcustompasswdfile.rst index 14469bf28..9300b3769 100644 --- a/docs/client_api/api/reloadcustompasswdfile.rst +++ b/docs/client_api/api/reloadcustompasswdfile.rst @@ -68,6 +68,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadcustom - On the client, the password file should be readable only by the 'user' itself Usage: + --reloadcustompasswdfile The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/reloadpasswdfile.rst b/docs/client_api/api/reloadpasswdfile.rst index 0ffa87f37..8f62a147d 100644 --- a/docs/client_api/api/reloadpasswdfile.rst +++ b/docs/client_api/api/reloadpasswdfile.rst @@ -68,6 +68,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadpasswd - On the client, the password file should be readable only by the 'user' itself Usage: + --reloadpasswdfile The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/reloadwsfile.rst b/docs/client_api/api/reloadwsfile.rst index 51d21c25c..a2bc54443 100644 --- a/docs/client_api/api/reloadwsfile.rst +++ b/docs/client_api/api/reloadwsfile.rst @@ -59,8 +59,8 @@ The following help text is generated by :code:`ecflow_client --help=reloadwsfile -user4 -* # use this form if you want all users to have read access - Usage: + --reloadwsfile The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/replace.rst b/docs/client_api/api/replace.rst index 6e0f94eee..2b2f0cb6b 100644 --- a/docs/client_api/api/replace.rst +++ b/docs/client_api/api/replace.rst @@ -46,6 +46,7 @@ The following help text is generated by :code:`ecflow_client --help=replace` For more information use --help check. Usage: + --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1 --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted diff --git a/docs/client_api/api/requeue.rst b/docs/client_api/api/requeue.rst index 57e9f21cc..ef5a6663c 100644 --- a/docs/client_api/api/requeue.rst +++ b/docs/client_api/api/requeue.rst @@ -32,6 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=requeue` arg2 = list of node paths. The node paths must begin with a leading '/' character Usage: + --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1 --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies. --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2' diff --git a/docs/client_api/api/restore.rst b/docs/client_api/api/restore.rst index d471438da..51e9fc9d8 100644 --- a/docs/client_api/api/restore.rst +++ b/docs/client_api/api/restore.rst @@ -45,7 +45,9 @@ The following help text is generated by :code:`ecflow_client --help=restore` In this example task '/s/frestore_from_task/t1' is only triggered if 'farchive_now' is archived, then when t1 completes it will restore family 'farchive_now' - Usage:: + + Usage: + --restore=/s1/f1 # restore family /s1/f1 --restore=/s1 /s2 # restore suites /s1 and /s2 diff --git a/docs/client_api/api/resume.rst b/docs/client_api/api/resume.rst index 1f1b83608..8707d725f 100644 --- a/docs/client_api/api/resume.rst +++ b/docs/client_api/api/resume.rst @@ -22,7 +22,9 @@ The following help text is generated by :code:`ecflow_client --help=resume` ------ Resume the given node. This allows job generation for the given node, or any child node. - Usage:: + + Usage: + --resume=/s1/f1/t1 # resume task s1/f1/t1 --resume=/s1 /s2 # resume suites /s1 and /s2 diff --git a/docs/client_api/api/server_load.rst b/docs/client_api/api/server_load.rst index 56ee9bd5a..f2e16cbf7 100644 --- a/docs/client_api/api/server_load.rst +++ b/docs/client_api/api/server_load.rst @@ -39,6 +39,7 @@ The following help text is generated by :code:`ecflow_client --help=server_load` rather than requesting the log path from the server. Usage: + --server_load=/path/to_log_file # Parses log and generate gnuplot files --server_load # Log file path is requested from server # which is then used to generate gnuplot files diff --git a/docs/client_api/api/server_version.rst b/docs/client_api/api/server_version.rst index ff62f5400..b6b656280 100644 --- a/docs/client_api/api/server_version.rst +++ b/docs/client_api/api/server_version.rst @@ -22,7 +22,9 @@ The following help text is generated by :code:`ecflow_client --help=server_versi -------------- Returns the version number of the server + Usage: + --server_version Writes the version to standard output diff --git a/docs/client_api/api/show.rst b/docs/client_api/api/show.rst index dfa153da3..48f3e453a 100644 --- a/docs/client_api/api/show.rst +++ b/docs/client_api/api/show.rst @@ -48,6 +48,7 @@ The following help text is generated by :code:`ecflow_client --help=show` trigger AST No Yes No Usage: + --group="get ; show" --group="get ; show defs" # same as the previous example --group="get ; show state" # Show all state for the node tree diff --git a/docs/client_api/api/status.rst b/docs/client_api/api/status.rst index 8774f7ce8..c41c0cdc4 100644 --- a/docs/client_api/api/status.rst +++ b/docs/client_api/api/status.rst @@ -35,7 +35,9 @@ The following help text is generated by :code:`ecflow_client --help=status` - state is active but it can't find process id, i.e. ECF_RID - the status command does not exit cleanly When this happens a flag is set, STATUSCMD_FAILED, which is visible in the GUI - Usage:: + + Usage: + --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file diff --git a/docs/client_api/api/suspend.rst b/docs/client_api/api/suspend.rst index 0f25ddbbc..c1f8cf2c5 100644 --- a/docs/client_api/api/suspend.rst +++ b/docs/client_api/api/suspend.rst @@ -22,7 +22,9 @@ The following help text is generated by :code:`ecflow_client --help=suspend` ------- Suspend the given node. This prevents job generation for the given node, or any child node. - Usage:: + + Usage: + --suspend=/s1/f1/t1 # suspend task s1/f1/t1 --suspend=/s1 /s2 # suspend suites /s1 and /s2 diff --git a/docs/client_api/api/wait.rst b/docs/client_api/api/wait.rst index 1de2ab3d6..25ffd8a11 100644 --- a/docs/client_api/api/wait.rst +++ b/docs/client_api/api/wait.rst @@ -26,6 +26,7 @@ The following help text is generated by :code:`ecflow_client --help=wait` arg1 = string(expression) Usage: + ecflow_client --wait="/suite/taskx == complete" The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/why.rst b/docs/client_api/api/why.rst index a2c0b1672..03dc55e64 100644 --- a/docs/client_api/api/why.rst +++ b/docs/client_api/api/why.rst @@ -28,7 +28,9 @@ The following help text is generated by :code:`ecflow_client --help=why` Will return reason why the node is holding and for all its children. If no arguments supplied will report on all nodes arg = node path | arg = NULL + Usage: + --group="get; why" # returns why for all holding nodes --group="get; why=/suite/family" # returns why for a specific node diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 35ac01a89..437e88c6a 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -25,6 +25,7 @@ "Otherwise the blocking period is defined by ECF_TIMEOUT.", "", "Usage:", + "", " ecflow_client --abort=reasonX" ], "arguments": [ @@ -189,7 +190,8 @@ " endfamily", "endsuite", "", - "Usage::", + "Usage:", + "", " --archive=/s1 # archive suite s1", " --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2", " --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" @@ -209,7 +211,9 @@ " force means reset the begin status on the suites and bypass checks.", " This is only required if suite-name is provide as the first argument", " Using force can cause the creation of zombies", + "", "Usage:", + "", "--begin # will begin all suites", "--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted", "--begin=\"mySuite\" # begin playing suite of name 'mySuite'", @@ -226,7 +230,9 @@ "Add a set of suites, to an existing handle.", " arg1 = handle(integer) # The handle must be an integer that is > 0", " arg2 = names # should be a list of suite names, names not in the definition are ignored", + "", "Usage:", + "", " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10", "An error is returned if the handle had not previously been registered", "The handle is created with --ch_register command", @@ -243,7 +249,9 @@ "Change an existing handle so that new suites can be added automatically.", " arg1 = handle(integer) # The handle must be an integer that is > 0", " arg2 = true | false # true means add new suites to my list, when they are created", + "", "Usage:", + "", " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it", " --ch_auto_add=10 false # modify handle 10 so that no new suites are added", "The handle is created with --ch_register command", @@ -260,7 +268,9 @@ "Drop/de-register the client handle.", "Un-used handle should be dropped otherwise they will stay, in the server.", " arg1 = handle(integer) # The handle must be an integer that is > 0", + "", "Usage:", + "", " --ch_drop=10 # drop the client handle 10", "An error is returned if the handle had not previously been registered", "The handle stored on the local client is set to zero", @@ -278,7 +288,9 @@ "If no user provided will drop for current user. Client must ensure un-used handle are dropped", "otherwise they will stay, in the server.", " arg1 = user # The user to be drooped, if left empty drop current user ", + "", "Usage:", + "", " --ch_drop_user=ma0 # drop all handles associated with user ma0", " --ch_drop_user # drop all handles associated with current user", "An error is returned if no registered handles", @@ -302,7 +314,9 @@ "This command affects news() and sync() commands", " arg1 = true | false # true means add new suites to my list, when they are created", " arg2 = names # should be a list of suite names, names not in the definition are ignored", + "", "Usage:", + "", " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites", " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only", " --ch_register=false # register handle, suites will be added later on", @@ -321,7 +335,9 @@ "Remove a set of suites, from an existing handle.", " arg1 = handle(integer) # The handle must be an integer that is > 0", " arg2 = names # should be a list of suite names, names not in the definition are ignored", + "", "Usage:", + "", " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10", "The handle is created with --ch_register command", "To list all suites and handles use --ch_suites" @@ -347,7 +363,9 @@ "(Note: On the client side unresolved paths in trigger expressions must", "have an associated 'extern' specified)", " arg = [ _all_ | / | list of node paths ]", + "", "Usage:", + "", " --check=_all_ # Checks all the suites", " --check=/ # Checks all the suites", " --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" @@ -392,7 +410,9 @@ " : This specifies the interval in seconds when server should automatically check pt.", " This will only take effect of mode is on_time/CHECK_ON_TIME", " Should ideally be a value greater than 60 seconds, default is 120 seconds", + "", "Usage:", + "", " --check_pt", " Immediately check point the definition held in the server", " --check_pt=never", @@ -426,6 +446,7 @@ " arg1(--remove)(optional) = a list of variables to removed from this task", "", "Usage:", + "", " ecflow_client --complete", " ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ], @@ -469,7 +490,9 @@ " arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt", " arg3 = node paths | _all_ # _all_ means delete all suites", " # node paths must start with a leading '/'", + "", "Usage:", + "", " --delete=_all_ # Delete all suites in server. Use with care.", " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt", " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted", @@ -485,7 +508,9 @@ "description": [ "Returns the edit history associated with a Node.", "Can also be used to clear the edit history.", - "Usage::", + "", + "Usage:", + "", " --edit_history=/s1/f1/t1 # return history of changes for the given node", " --edit_history=clear # clear/purge *ALL* edit history from all nodes.", "" @@ -521,7 +546,9 @@ " arg4 = create_alias (optional) default value is false, for use with 'submit_file' option", " arg5 = no_run (optional) default value is false, i.e immediately run the alias", " is no_run is specified the alias in only created", + "", "Usage:", + "", "--edit_script=/path/to/task edit > script_file", " server returns script with the used variables to standard out", " The user can choose to edit this file", @@ -567,6 +594,7 @@ "The default can be overridden by using zombie attributes.", "", "Usage:", + "", " ecflow_client --event=ev # set the event, default since event initial value is clear", " ecflow_client --event=ev set # set the event, explicit", " ecflow_client --event=ev clear # clear the event, use when event initial value is set", @@ -628,7 +656,9 @@ " Set repeat variables to last value, only works in conjunction", " with recursive option", " arg4 = path_to_node or path_to_node:: paths must begin with '/'", + "", "Usage:", + "", " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete", " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task", " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1", @@ -670,7 +700,9 @@ " arg4 = (optional) time", " Free all time dependencies i.e time, day, today, cron", " arg5 = List of paths. At least one required. Must start with a leading '/'", + "", "Usage:", + "", " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2", " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1", " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1" @@ -687,7 +719,9 @@ "Get all suite node tree's from the server and write to standard out.", "The output is parse-able, and can be used to re-load the definition", " arg = NULL | arg = node path", + "", "Usage:", + "", " --get # gets the definition from the server,and writes to standard out", " --get=/s1 # gets the suite from the server,and writes to standard out" ] @@ -703,7 +737,9 @@ "This will include event, meter, node state, trigger and time state.", "The output is written to standard out.", " arg = NULL | arg = node path", + "", "Usage:", + "", " --get_state # gets the definition from the server,and writes to standard out", " --get_state=/s1 # gets the suite from the server,and writes to standard out" ] @@ -719,7 +755,9 @@ "Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt", "provide 'yes' as an additional parameter. See example below.", " arg = string", + "", "Usage:", + "", " --group=\"halt=yes; reloadwsfile; restart;\"", " # halt server,bypass the confirmation prompt,", " # reload white list file, restart server", @@ -766,6 +804,7 @@ "Otherwise the blocking period is defined by ECF_TIMEOUT.", "", "Usage:", + "", " ecflow_client --init=$$", " ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ], @@ -815,7 +854,9 @@ "The command should be written in such a way that the output is written to %ECF_JOB%.kill", "as this allow the --file command to report the output: .e.e.", " /home/ma/emos/bin/ecfkill %USER% %HOST% %ECF_RID% %ECF_JOB% > %ECF_JOB%.kill 2>&1::", - "Usage::", + "", + "Usage:", + "", " --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2", " --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1" ] @@ -838,6 +879,7 @@ "The default can be overridden by using zombie attributes.", "", "Usage:", + "", " ecflow_client --label=progressed merlin" ], "arguments": [ @@ -869,7 +911,9 @@ "This command can also be used to load a checkpoint file into the server", " arg1 = path to the definition file or checkpoint file", " arg2 = (optional) [ force | check_only | print | stats ] # default = false for all", + "", "Usage:", + "", "--load=/my/home/exotic.def # will error if suites of same name exists", "--load=/my/home/exotic.def force # overwrite suite's of same name in the server", "--load=/my/home/exotic.def check_only # Just check, don't send to server", @@ -908,7 +952,9 @@ " arg2 = [ new_path | optional last n lines ]", " if get specified can specify lines to get. Value must be convertible to an integer", " Otherwise if arg1 is 'new' then the second argument must be a path", + "", "Usage:", + "", " --log=get # Write the last 100 lines of the log file to standard out", " --log=get 200 # Write the last 200 lines of the log file to standard out", " --log=clear # Clear the log file. The log is now empty", @@ -935,6 +981,7 @@ "The default can be overridden by using zombie attributes.", "", "Usage:", + "", " ecflow_client --meter=my_meter 20" ], "arguments": [ @@ -973,6 +1020,7 @@ "Show trigger AST No Yes No", "", "Usage:", + "", " --migrate # show all suites", " --migrate=/s1 # show state for suite s1", "" @@ -995,7 +1043,9 @@ "description": [ "Writes the input string to the log file.", " arg1 = string", + "", "Usage:", + "", " --msg=\"place me in the log file\"" ] }, @@ -1041,7 +1091,9 @@ "This command can fail because:", "- The node path does not exist in the server", "- The order_type is not does not match one of arg2", + "", "Usage:", + "", " --order=/suite/f1 top # move node f1 to the top" ] }, @@ -1053,7 +1105,9 @@ "summary": "Check if server is running on given host/port. Result reported to standard output.", "description": [ "Check if server is running on given host/port. Result reported to standard output.", + "", "Usage:", + "", " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144", " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,", " # otherwise default port of 3141", @@ -1082,7 +1136,9 @@ " then the source node must correspond to a suite.", "- If the source node is added as a child, then its name must be unique", " amongst its peers", + "", "Usage:", + "", " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)" ] }, @@ -1126,6 +1182,7 @@ " arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat", "", "Usage:", + "", " ecflow_client --query state / # return top level state to standard out", " ecflow_client --query state /path/to/node # return node state to standard out", " ecflow_client --query dstate /path/to/node # state that can included suspended", @@ -1167,6 +1224,7 @@ "search for the queue up the node hierarchy. If no queue found, command fails", "", "Usage:", + "", "step=\"\"", "QNAME=\"my_queue_name\"", "while [1 == 1 ] ; do", @@ -1265,6 +1323,7 @@ " - On the client, the password file should be readable only by the 'user' itself", "", "Usage:", + "", " --reloadcustompasswdfile" ] }, @@ -1322,6 +1381,7 @@ " - On the client, the password file should be readable only by the 'user' itself", "", "Usage:", + "", " --reloadpasswdfile" ] }, @@ -1370,8 +1430,8 @@ "-user4", "-* # use this form if you want all users to have read access", "", - "", "Usage:", + "", " --reloadwsfile" ] }, @@ -1407,6 +1467,7 @@ "For more information use --help check.", "", "Usage:", + "", " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1", " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted" ] @@ -1429,6 +1490,7 @@ " arg2 = list of node paths. The node paths must begin with a leading '/' character", "", "Usage:", + "", " --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1", " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.", " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'" @@ -1483,7 +1545,9 @@ "", "In this example task '/s/frestore_from_task/t1' is only triggered if 'farchive_now'", "is archived, then when t1 completes it will restore family 'farchive_now'", - "Usage::", + "", + "Usage:", + "", " --restore=/s1/f1 # restore family /s1/f1", " --restore=/s1 /s2 # restore suites /s1 and /s2" ] @@ -1508,7 +1572,9 @@ "summary": "Resume the given node. This allows job generation for the given node, or any child node.", "description": [ "Resume the given node. This allows job generation for the given node, or any child node.", - "Usage::", + "", + "Usage:", + "", " --resume=/s1/f1/t1 # resume task s1/f1/t1", " --resume=/s1 /s2 # resume suites /s1 and /s2", "" @@ -1571,6 +1637,7 @@ "rather than requesting the log path from the server.", "", "Usage:", + "", " --server_load=/path/to_log_file # Parses log and generate gnuplot files", " --server_load # Log file path is requested from server", " # which is then used to generate gnuplot files", @@ -1594,7 +1661,9 @@ "summary": "Returns the version number of the server", "description": [ "Returns the version number of the server", + "", "Usage:", + "", " --server_version", " Writes the version to standard output", "" @@ -1634,6 +1703,7 @@ "trigger AST No Yes No", "", "Usage:", + "", " --group=\"get ; show\"", " --group=\"get ; show defs\" # same as the previous example", " --group=\"get ; show state\" # Show all state for the node tree", @@ -1707,7 +1777,9 @@ " - state is active but it can't find process id, i.e. ECF_RID", " - the status command does not exit cleanly", "When this happens a flag is set, STATUSCMD_FAILED, which is visible in the GUI", - "Usage::", + "", + "Usage:", + "", " --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat", " --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" ] @@ -1728,7 +1800,9 @@ "summary": "Suspend the given node. This prevents job generation for the given node, or any child node.", "description": [ "Suspend the given node. This prevents job generation for the given node, or any child node.", - "Usage::", + "", + "Usage:", + "", " --suspend=/s1/f1/t1 # suspend task s1/f1/t1", " --suspend=/s1 /s2 # suspend suites /s1 and /s2", "" @@ -1801,6 +1875,7 @@ " arg1 = string(expression)", "", "Usage:", + "", " ecflow_client --wait=\"/suite/taskx == complete\"" ], "arguments": [ @@ -1826,7 +1901,9 @@ "Will return reason why the node is holding and for all its children.", "If no arguments supplied will report on all nodes", " arg = node path | arg = NULL", + "", "Usage:", + "", " --group=\"get; why\" # returns why for all holding nodes", " --group=\"get; why=/suite/family\" # returns why for a specific node" ] From d3643c41df98ea0a9457bd5461f13e601a200d97 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 07:12:13 +0100 Subject: [PATCH 46/49] Tidy CLI Usage examples and drop the unused usage field Remove the redundant "ecflow_client" prefix from every Usage example and indent all options to 4 spaces, for consistent help output. Delete the "usage" field from the schema and all commands: it merely duplicated the description's Usage text and was read by nothing. Also strip the trailing blank line from descriptions that had one, and regenerate the CLI documentation. The manifest formatting (topics, arrays) is normalised in passing. --- docs/client_api/api/abort.rst | 2 +- docs/client_api/api/alter.rst | 51 +- docs/client_api/api/archive.rst | 6 +- docs/client_api/api/begin.rst | 8 +- docs/client_api/api/ch_add.rst | 2 +- docs/client_api/api/ch_auto_add.rst | 4 +- docs/client_api/api/ch_drop.rst | 2 +- docs/client_api/api/ch_drop_user.rst | 4 +- docs/client_api/api/ch_register.rst | 11 +- docs/client_api/api/ch_rem.rst | 4 +- docs/client_api/api/check.rst | 6 +- docs/client_api/api/check_pt.rst | 26 +- docs/client_api/api/complete.rst | 4 +- docs/client_api/api/delete.rst | 8 +- docs/client_api/api/edit_history.rst | 5 +- docs/client_api/api/edit_script.rst | 40 +- docs/client_api/api/event.rst | 7 +- docs/client_api/api/force.rst | 25 +- docs/client_api/api/free-dep.rst | 6 +- docs/client_api/api/get.rst | 4 +- docs/client_api/api/get_state.rst | 4 +- docs/client_api/api/group.rst | 14 +- docs/client_api/api/halt.rst | 6 +- docs/client_api/api/http.rst | 1 - docs/client_api/api/https.rst | 1 - docs/client_api/api/init.rst | 4 +- docs/client_api/api/kill.rst | 4 +- docs/client_api/api/label.rst | 2 +- docs/client_api/api/load.rst | 13 +- docs/client_api/api/log.rst | 13 +- docs/client_api/api/meter.rst | 2 +- docs/client_api/api/migrate.rst | 1 - docs/client_api/api/msg.rst | 2 +- docs/client_api/api/order.rst | 2 +- docs/client_api/api/ping.rst | 10 +- docs/client_api/api/plug.rst | 2 +- docs/client_api/api/query.rst | 29 +- docs/client_api/api/queue.rst | 1 - .../client_api/api/reloadcustompasswdfile.rst | 2 +- docs/client_api/api/reloadpasswdfile.rst | 2 +- docs/client_api/api/reloadwsfile.rst | 2 +- docs/client_api/api/replace.rst | 4 +- docs/client_api/api/requeue.rst | 6 +- docs/client_api/api/restore.rst | 4 +- docs/client_api/api/resume.rst | 5 +- docs/client_api/api/run.rst | 14 +- docs/client_api/api/server_load.rst | 18 +- docs/client_api/api/server_version.rst | 5 +- docs/client_api/api/shutdown.rst | 6 +- docs/client_api/api/status.rst | 4 +- docs/client_api/api/suspend.rst | 5 +- docs/client_api/api/terminate.rst | 5 +- docs/client_api/api/wait.rst | 2 +- docs/client_api/api/why.rst | 4 +- docs/client_api/api/zombie_adopt.rst | 5 +- docs/client_api/api/zombie_block.rst | 5 +- docs/client_api/api/zombie_fail.rst | 5 +- docs/client_api/api/zombie_fob.rst | 5 +- docs/client_api/api/zombie_kill.rst | 5 +- docs/client_api/api/zombie_remove.rst | 5 +- docs/client_api/help.json | 521 +++++++++--------- docs/client_api/help.schema.json | 6 - 62 files changed, 515 insertions(+), 466 deletions(-) diff --git a/docs/client_api/api/abort.rst b/docs/client_api/api/abort.rst index dcf975499..f7bfc2e52 100644 --- a/docs/client_api/api/abort.rst +++ b/docs/client_api/api/abort.rst @@ -32,7 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=abort` Usage: - ecflow_client --abort=reasonX + --abort=reasonX The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/alter.rst b/docs/client_api/api/alter.rst index 8be84df10..277c283db 100644 --- a/docs/client_api/api/alter.rst +++ b/docs/client_api/api/alter.rst @@ -114,46 +114,45 @@ The following help text is generated by :code:`ecflow_client --help=alter` Usage: - ecflow_client --alter=add variable "value" / # add server variable - ecflow_client --alter=add variable "value" /path/to/node # add node variable + --alter=add variable "value" / # add server variable + --alter=add variable "value" /path/to/node # add node variable - ecflow_client --alter=add time "+00:20" /path/to/node + --alter=add time "+00:20" /path/to/node - ecflow_client --alter=add date "01.*.*" /path/to/node + --alter=add date "01.*.*" /path/to/node - ecflow_client --alter=add day "sunday" /path/to/node + --alter=add day "sunday" /path/to/node - ecflow_client --alter=add label "label_value" /path/to/node + --alter=add label "label_value" /path/to/node - ecflow_client --alter=add event "set"|"clear" /path/to/node + --alter=add event "set"|"clear" /path/to/node - ecflow_client --alter=add meter ",,value" /path/to/node + --alter=add meter ",,value" /path/to/node - ecflow_client --alter=add late "-s 00:01 -a 14:30 -c +00:01" /path/to/node + --alter=add late "-s 00:01 -a 14:30 -c +00:01" /path/to/node - ecflow_client --alter=add limit mars "100" /path/to/node + --alter=add limit mars "100" /path/to/node - ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name "10" /path/to/node + --alter=add inlimit /path/to/node/withlimit:limit_name "10" /path/to/node - ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name "-s 10" /path/to/node + --alter=add inlimit /path/to/node/withlimit:limit_name "-s 10" /path/to/node - ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name "-n 10" /path/to/node + --alter=add inlimit /path/to/node/withlimit:limit_name "-n 10" /path/to/node - # zombie attributes have the following structure: - `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time` - zombie_type = "user" | "ecf" | "path" | "ecf_pid" | "ecf_passwd" | "ecf_pid_passwd" - client_side_action = "fob" | "fail" | "block" - server_side_action = "adopt" | "delete" | "kill" - child = "init" | "event" | "meter" | "label" | "wait" | "abort" | "complete" | "queue" - zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60 + # zombie attributes have the following structure: + `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time` + zombie_type = "user" | "ecf" | "path" | "ecf_pid" | "ecf_passwd" | "ecf_pid_passwd" + client_side_action = "fob" | "fail" | "block" + server_side_action = "adopt" | "delete" | "kill" + child = "init" | "event" | "meter" | "label" | "wait" | "abort" | "complete" | "queue" + zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60 - ecflow_client --alter=add zombie "ecf:fail::" /path/to/node # ask system zombies to fail - ecflow_client --alter=add zombie "user:fail::" /path/to/node # ask user generated zombies to fail - ecflow_client --alter=add zombie "path:fail::" /path/to/node # ask path zombies to fail - - ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED - ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode + --alter=add zombie "ecf:fail::" /path/to/node # ask system zombies to fail + --alter=add zombie "user:fail::" /path/to/node # ask user generated zombies to fail + --alter=add zombie "path:fail::" /path/to/node # ask path zombies to fail + --alter=delete variable FRED /path/to/node # delete variable FRED + --alter=delete variable /path/to/node # delete *ALL* variables on the given snode The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/archive.rst b/docs/client_api/api/archive.rst index 6fdf8c870..618a83f4e 100644 --- a/docs/client_api/api/archive.rst +++ b/docs/client_api/api/archive.rst @@ -55,9 +55,9 @@ The following help text is generated by :code:`ecflow_client --help=archive` Usage: - --archive=/s1 # archive suite s1 - --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2 - --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks + --archive=/s1 # archive suite s1 + --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2 + --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/begin.rst b/docs/client_api/api/begin.rst index 4de6a70b4..d63523ab4 100644 --- a/docs/client_api/api/begin.rst +++ b/docs/client_api/api/begin.rst @@ -31,10 +31,10 @@ The following help text is generated by :code:`ecflow_client --help=begin` Usage: - --begin # will begin all suites - --begin="--force" # reset and then begin all suites, bypassing any checks. Note: string must be quoted - --begin="mySuite" # begin playing suite of name 'mySuite' - --begin="mySuite --force" # reset and begin playing suite 'mySuite', bypass check + --begin # will begin all suites + --begin="--force" # reset and then begin all suites, bypassing any checks. Note: string must be quoted + --begin="mySuite" # begin playing suite of name 'mySuite' + --begin="mySuite --force" # reset and begin playing suite 'mySuite', bypass check The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/ch_add.rst b/docs/client_api/api/ch_add.rst index 62fd19f9e..818c072ee 100644 --- a/docs/client_api/api/ch_add.rst +++ b/docs/client_api/api/ch_add.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_add` Usage: - --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10 + --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10 An error is returned if the handle had not previously been registered The handle is created with --ch_register command To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_auto_add.rst b/docs/client_api/api/ch_auto_add.rst index b0ccee893..f7a9674cc 100644 --- a/docs/client_api/api/ch_auto_add.rst +++ b/docs/client_api/api/ch_auto_add.rst @@ -27,8 +27,8 @@ The following help text is generated by :code:`ecflow_client --help=ch_auto_add` Usage: - --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it - --ch_auto_add=10 false # modify handle 10 so that no new suites are added + --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it + --ch_auto_add=10 false # modify handle 10 so that no new suites are added The handle is created with --ch_register command To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_drop.rst b/docs/client_api/api/ch_drop.rst index a23bcc7c8..8488b070f 100644 --- a/docs/client_api/api/ch_drop.rst +++ b/docs/client_api/api/ch_drop.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop` Usage: - --ch_drop=10 # drop the client handle 10 + --ch_drop=10 # drop the client handle 10 An error is returned if the handle had not previously been registered The handle stored on the local client is set to zero To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_drop_user.rst b/docs/client_api/api/ch_drop_user.rst index c29e9b8bd..0f9b7a78f 100644 --- a/docs/client_api/api/ch_drop_user.rst +++ b/docs/client_api/api/ch_drop_user.rst @@ -28,8 +28,8 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop_user Usage: - --ch_drop_user=ma0 # drop all handles associated with user ma0 - --ch_drop_user # drop all handles associated with current user + --ch_drop_user=ma0 # drop all handles associated with user ma0 + --ch_drop_user # drop all handles associated with current user An error is returned if no registered handles To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_register.rst b/docs/client_api/api/ch_register.rst index c0360cef4..1ae032d69 100644 --- a/docs/client_api/api/ch_register.rst +++ b/docs/client_api/api/ch_register.rst @@ -34,11 +34,12 @@ The following help text is generated by :code:`ecflow_client --help=ch_register` Usage: - --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites - --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only - --ch_register=false # register handle, suites will be added later on - --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites - # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first + --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites + --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only + --ch_register=false # register handle, suites will be added later on + --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites + # The client handle as the first argument is typically used by GUI/python + # When the client handle is no zero, then it is dropped first To list all suites and handles use --ch_suites The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/ch_rem.rst b/docs/client_api/api/ch_rem.rst index 363d9eec2..dfd7e6fe6 100644 --- a/docs/client_api/api/ch_rem.rst +++ b/docs/client_api/api/ch_rem.rst @@ -27,8 +27,10 @@ The following help text is generated by :code:`ecflow_client --help=ch_rem` Usage: - --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10 + --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10 + The handle is created with --ch_register command + To list all suites and handles use --ch_suites The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/check.rst b/docs/client_api/api/check.rst index a8a60eccb..6dec4ada1 100644 --- a/docs/client_api/api/check.rst +++ b/docs/client_api/api/check.rst @@ -29,9 +29,9 @@ The following help text is generated by :code:`ecflow_client --help=check` Usage: - --check=_all_ # Checks all the suites - --check=/ # Checks all the suites - --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1 + --check=_all_ # Checks all the suites + --check=/ # Checks all the suites + --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/check_pt.rst b/docs/client_api/api/check_pt.rst index 516f218e3..cddd2acc4 100644 --- a/docs/client_api/api/check_pt.rst +++ b/docs/client_api/api/check_pt.rst @@ -42,19 +42,19 @@ The following help text is generated by :code:`ecflow_client --help=check_pt` Usage: - --check_pt - Immediately check point the definition held in the server - --check_pt=never - Switch off check pointing - --check_pt=on_time - Start automatic check pointing at the interval stored in the server - --check_pt=180 - Change the check pt interval to 180 seconds - --check_pt=on_time:90 - Change mode and interval, to automatic check pointing every 90 seconds - --check_pt=alarm:35 - Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds - set the late flag on the server. + --check_pt + Immediately check point the definition held in the server + --check_pt=never + Switch off check pointing + --check_pt=on_time + Start automatic check pointing at the interval stored in the server + --check_pt=180 + Change the check pt interval to 180 seconds + --check_pt=on_time:90 + Change mode and interval, to automatic check pointing every 90 seconds + --check_pt=alarm:35 + Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds + set the late flag on the server. The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/complete.rst b/docs/client_api/api/complete.rst index 48c51998f..44c05c102 100644 --- a/docs/client_api/api/complete.rst +++ b/docs/client_api/api/complete.rst @@ -33,8 +33,8 @@ The following help text is generated by :code:`ecflow_client --help=complete` Usage: - ecflow_client --complete - ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task + --complete + --complete --remove name1 name2 # delete variables name1 and name2 on the task The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/delete.rst b/docs/client_api/api/delete.rst index 74b7adb11..0755b1f38 100644 --- a/docs/client_api/api/delete.rst +++ b/docs/client_api/api/delete.rst @@ -29,10 +29,10 @@ The following help text is generated by :code:`ecflow_client --help=delete` Usage: - --delete=_all_ # Delete all suites in server. Use with care. - --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt - --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted - --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt + --delete=_all_ # Delete all suites in server. Use with care. + --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt + --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted + --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/edit_history.rst b/docs/client_api/api/edit_history.rst index 34553b0a7..138c90f05 100644 --- a/docs/client_api/api/edit_history.rst +++ b/docs/client_api/api/edit_history.rst @@ -26,9 +26,8 @@ The following help text is generated by :code:`ecflow_client --help=edit_history Usage: - --edit_history=/s1/f1/t1 # return history of changes for the given node - --edit_history=clear # clear/purge *ALL* edit history from all nodes. - + --edit_history=/s1/f1/t1 # return history of changes for the given node + --edit_history=clear # clear/purge *ALL* edit history from all nodes. The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/edit_script.rst b/docs/client_api/api/edit_script.rst index 780ab15bd..a21b58abf 100644 --- a/docs/client_api/api/edit_script.rst +++ b/docs/client_api/api/edit_script.rst @@ -47,31 +47,31 @@ The following help text is generated by :code:`ecflow_client --help=edit_script` Usage: - --edit_script=/path/to/task edit > script_file - server returns script with the used variables to standard out - The user can choose to edit this file + --edit_script=/path/to/task edit > script_file + server returns script with the used variables to standard out + The user can choose to edit this file - --edit_script=/path/to/task pre_process > pre_processed_script_file - server will pre process the ecf file accessible from the server - (i.e expand all %includes) and return the file to standard out + --edit_script=/path/to/task pre_process > pre_processed_script_file + server will pre process the ecf file accessible from the server + (i.e expand all %includes) and return the file to standard out - --edit_script=/path/to/task submit script_file - Will extract the used variables in the 'script_file' and will uses these - variables during variable substitution of the ecf file accessible by the - server. This is then submitted as a job + --edit_script=/path/to/task submit script_file + Will extract the used variables in the 'script_file' and will uses these + variables during variable substitution of the ecf file accessible by the + server. This is then submitted as a job - --edit_script=/path/to/task pre_process_file file_to_pre_process - The server will pre-process the user supplied file and return the contents - to standard out. This pre-processing is the same as job file processing, - but on a arbitrary file + --edit_script=/path/to/task pre_process_file file_to_pre_process + The server will pre-process the user supplied file and return the contents + to standard out. This pre-processing is the same as job file processing, + but on a arbitrary file - --edit_script=/path/to/task submit_file file_to_submit - Will extract the used variables in the 'file_to_submit' and will uses these - variables during variable substitution, the file is then submitted for job - generation by the server + --edit_script=/path/to/task submit_file file_to_submit + Will extract the used variables in the 'file_to_submit' and will uses these + variables during variable substitution, the file is then submitted for job + generation by the server - --edit_script=/path/to/task submit_file file_to_submit create_alias - Like the the previous example but will create and run as an alias + --edit_script=/path/to/task submit_file file_to_submit create_alias + Like the the previous example but will create and run as an alias The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/event.rst b/docs/client_api/api/event.rst index 8ddc7907e..83719a73c 100644 --- a/docs/client_api/api/event.rst +++ b/docs/client_api/api/event.rst @@ -33,10 +33,9 @@ The following help text is generated by :code:`ecflow_client --help=event` Usage: - ecflow_client --event=ev # set the event, default since event initial value is clear - ecflow_client --event=ev set # set the event, explicit - ecflow_client --event=ev clear # clear the event, use when event initial value is set - + --event=ev # set the event, default since event initial value is clear + --event=ev set # set the event, explicit + --event=ev clear # clear the event, use when event initial value is set The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/force.rst b/docs/client_api/api/force.rst index a02f5cc37..7db183582 100644 --- a/docs/client_api/api/force.rst +++ b/docs/client_api/api/force.rst @@ -39,19 +39,22 @@ The following help text is generated by :code:`ecflow_client --help=force` Usage: - --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete - --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task - --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1 + --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete + --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task + --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1 + Effect: - Consider the effect of forcing complete when the current time is at 09:00 - suite s1 - task t1; time 12:00 # will complete straight away - task t2; time 10:00 13:00 01:00 # will complete on fourth attempt - --force=complete /s1/t1 /s1/t2 - When we have a time range(i.e as shown with task t2), it is re-queued and the - next time slot is incremented for each complete, until it expires, and the task completes. - Use the Why command, to show next run time (i.e. next time slot) + Consider the effect of applying `--force=complete /s1/t1 /s1/t2` at 09:00 + + suite s1 + task t1; time 12:00 # will complete straight away + task t2; time 10:00 13:00 01:00 # will complete on fourth attempt + + Specifying a time range, as shown with task t2, means the task is re-queued and the + next time slot is incremented for each complete, until it expires, and the task completes. + + Use the Why command, to show next run time (i.e. next time slot) The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/free-dep.rst b/docs/client_api/api/free-dep.rst index 88ed3a810..5885d40b3 100644 --- a/docs/client_api/api/free-dep.rst +++ b/docs/client_api/api/free-dep.rst @@ -35,9 +35,9 @@ The following help text is generated by :code:`ecflow_client --help=free-dep` Usage: - --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2 - --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1 - --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1 + --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2 + --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1 + --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/get.rst b/docs/client_api/api/get.rst index ad54c5c48..3cb0d0e13 100644 --- a/docs/client_api/api/get.rst +++ b/docs/client_api/api/get.rst @@ -55,8 +55,8 @@ The following help text is generated by :code:`ecflow_client --help=get` Usage: - --get # gets the definition from the server,and writes to standard out - --get=/s1 # gets the suite from the server,and writes to standard out + --get # gets the definition from the server,and writes to standard out + --get=/s1 # gets the suite from the server,and writes to standard out The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/get_state.rst b/docs/client_api/api/get_state.rst index 882c9c01d..d07250151 100644 --- a/docs/client_api/api/get_state.rst +++ b/docs/client_api/api/get_state.rst @@ -28,8 +28,8 @@ The following help text is generated by :code:`ecflow_client --help=get_state` Usage: - --get_state # gets the definition from the server,and writes to standard out - --get_state=/s1 # gets the suite from the server,and writes to standard out + --get_state # gets the definition from the server,and writes to standard out + --get_state=/s1 # gets the suite from the server,and writes to standard out The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/group.rst b/docs/client_api/api/group.rst index e9c3cb478..99ff2a7e5 100644 --- a/docs/client_api/api/group.rst +++ b/docs/client_api/api/group.rst @@ -28,11 +28,15 @@ The following help text is generated by :code:`ecflow_client --help=group` Usage: - --group="halt=yes; reloadwsfile; restart;" - # halt server,bypass the confirmation prompt, - # reload white list file, restart server - --group="get; show" # get server defs, and write to standard output - --group="get=/s1; show state" # get suite 's1', and write state to standard output + --group="halt=yes; reloadwsfile; restart;" + # halt server,bypass the confirmation prompt, + # reload white list file, restart server + + --group="get; show" + # get server defs, and write to standard output + + --group="get=/s1; show state" + # get suite 's1', and write state to standard output The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/halt.rst b/docs/client_api/api/halt.rst index eda31dbb0..e65acef51 100644 --- a/docs/client_api/api/halt.rst +++ b/docs/client_api/api/halt.rst @@ -24,7 +24,11 @@ The following help text is generated by :code:`ecflow_client --help=halt` Stop server communication with jobs, and new job scheduling. Also stops automatic check pointing arg1 = yes(optional) # use to bypass confirmation prompt,i.e. - --halt=yes + + Usage: + + --halt=yes + The following table shows server behaviour in the different states. |----------------------------------------------------------------------------------| | Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing | diff --git a/docs/client_api/api/http.rst b/docs/client_api/api/http.rst index 2142647ee..80b289168 100644 --- a/docs/client_api/api/http.rst +++ b/docs/client_api/api/http.rst @@ -24,6 +24,5 @@ The following help text is generated by :code:`ecflow_client --help=http` Enables communication over HTTP between client/server. - diff --git a/docs/client_api/api/https.rst b/docs/client_api/api/https.rst index b1e0c594c..e3459f988 100644 --- a/docs/client_api/api/https.rst +++ b/docs/client_api/api/https.rst @@ -24,6 +24,5 @@ The following help text is generated by :code:`ecflow_client --help=https` Enables communication over HTTPS between client/server. - diff --git a/docs/client_api/api/init.rst b/docs/client_api/api/init.rst index 83a8713b6..891d6de6e 100644 --- a/docs/client_api/api/init.rst +++ b/docs/client_api/api/init.rst @@ -33,8 +33,8 @@ The following help text is generated by :code:`ecflow_client --help=init` Usage: - ecflow_client --init=$$ - ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task + --init=$$ + --init=$$ --add name=value name2=value2 # add/update variables to task The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/kill.rst b/docs/client_api/api/kill.rst index 0b24d6d5c..83ad7706e 100644 --- a/docs/client_api/api/kill.rst +++ b/docs/client_api/api/kill.rst @@ -30,8 +30,8 @@ The following help text is generated by :code:`ecflow_client --help=kill` Usage: - --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2 - --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1 + --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2 + --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/label.rst b/docs/client_api/api/label.rst index d269df1ae..56ba375b1 100644 --- a/docs/client_api/api/label.rst +++ b/docs/client_api/api/label.rst @@ -33,7 +33,7 @@ The following help text is generated by :code:`ecflow_client --help=label` Usage: - ecflow_client --label=progressed merlin + --label=progressed merlin The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/load.rst b/docs/client_api/api/load.rst index 8072dda9d..813ff3e7a 100644 --- a/docs/client_api/api/load.rst +++ b/docs/client_api/api/load.rst @@ -33,13 +33,12 @@ The following help text is generated by :code:`ecflow_client --help=load` Usage: - --load=/my/home/exotic.def # will error if suites of same name exists - --load=/my/home/exotic.def force # overwrite suite's of same name in the server - --load=/my/home/exotic.def check_only # Just check, don't send to server - --load=/my/home/exotic.def stats # Show defs statistics, don't send to server - --load=host1.3141.check # Load checkpoint file to the server - --load=host1.3141.check print # print definition to standard out in defs format - + --load=/my/home/exotic.def # will error if suites of same name exists + --load=/my/home/exotic.def force # overwrite suite's of same name in the server + --load=/my/home/exotic.def check_only # Just check, don't send to server + --load=/my/home/exotic.def stats # Show defs statistics, don't send to server + --load=host1.3141.check # Load checkpoint file to the server + --load=host1.3141.check print # print definition to standard out in defs format The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/log.rst b/docs/client_api/api/log.rst index 30f2f9ce9..28074e0f6 100644 --- a/docs/client_api/api/log.rst +++ b/docs/client_api/api/log.rst @@ -46,13 +46,12 @@ The following help text is generated by :code:`ecflow_client --help=log` Usage: - --log=get # Write the last 100 lines of the log file to standard out - --log=get 200 # Write the last 200 lines of the log file to standard out - --log=clear # Clear the log file. The log is now empty - --log=flush # Flush and close log file, next request will re-open log file - --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG - --log=new # Close and flush log file, and create a new log file using ECF_LOG variable - + --log=get # Write the last 100 lines of the log file to standard out + --log=get 200 # Write the last 200 lines of the log file to standard out + --log=clear # Clear the log file. The log is now empty + --log=flush # Flush and close log file, next request will re-open log file + --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG + --log=new # Close and flush log file, and create a new log file using ECF_LOG variable The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/meter.rst b/docs/client_api/api/meter.rst index 3b0785dd6..8fb7cf2e4 100644 --- a/docs/client_api/api/meter.rst +++ b/docs/client_api/api/meter.rst @@ -32,7 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=meter` Usage: - ecflow_client --meter=my_meter 20 + --meter=my_meter 20 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/migrate.rst b/docs/client_api/api/migrate.rst index b72f561d9..28c5e2887 100644 --- a/docs/client_api/api/migrate.rst +++ b/docs/client_api/api/migrate.rst @@ -40,7 +40,6 @@ The following help text is generated by :code:`ecflow_client --help=migrate` --migrate # show all suites --migrate=/s1 # show state for suite s1 - The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] diff --git a/docs/client_api/api/msg.rst b/docs/client_api/api/msg.rst index 84cc387ee..7d4499a37 100644 --- a/docs/client_api/api/msg.rst +++ b/docs/client_api/api/msg.rst @@ -26,7 +26,7 @@ The following help text is generated by :code:`ecflow_client --help=msg` Usage: - --msg="place me in the log file" + --msg="place me in the log file" The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/order.rst b/docs/client_api/api/order.rst index b57ddc3ff..15297a35c 100644 --- a/docs/client_api/api/order.rst +++ b/docs/client_api/api/order.rst @@ -45,7 +45,7 @@ The following help text is generated by :code:`ecflow_client --help=order` Usage: - --order=/suite/f1 top # move node f1 to the top + --order=/suite/f1 top # move node f1 to the top The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/ping.rst b/docs/client_api/api/ping.rst index 661b62aee..c8ade747c 100644 --- a/docs/client_api/api/ping.rst +++ b/docs/client_api/api/ping.rst @@ -25,11 +25,11 @@ The following help text is generated by :code:`ecflow_client --help=ping` Usage: - --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144 - --ping --host=fred # Check if server alive on host fred and port ECF_PORT, - # otherwise default port of 3141 - --ping # Check if server alive by using environment variables - # ECF_HOST and ECF_PORT + --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144 + --ping --host=fred # Check if server alive on host fred and port ECF_PORT, + # otherwise default port of 3141 + --ping # Check if server alive by using environment variables + # ECF_HOST and ECF_PORT If ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/plug.rst b/docs/client_api/api/plug.rst index 771ba253c..19c6097c6 100644 --- a/docs/client_api/api/plug.rst +++ b/docs/client_api/api/plug.rst @@ -37,7 +37,7 @@ The following help text is generated by :code:`ecflow_client --help=plug` Usage: - --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141) + --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141) The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/query.rst b/docs/client_api/api/query.rst index 362662316..380ecfa27 100644 --- a/docs/client_api/api/query.rst +++ b/docs/client_api/api/query.rst @@ -154,21 +154,20 @@ The following help text is generated by :code:`ecflow_client --help=query` Usage: - ecflow_client --query state / # return top level state to standard out - ecflow_client --query state /path/to/node # return node state to standard out - ecflow_client --query dstate /path/to/node # state that can included suspended - ecflow_client --query repeat /path/to/node # return the current value as a string - ecflow_client --query repeat /path/to/node prev # return the previous value as a string - ecflow_client --query repeat /path/to/node next # return the next value as a string - ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out - ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out - ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out - ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out - ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out - ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to standard out - ecflow_client --query variable /:var_name # returns the server variable value to standard out - ecflow_client --query trigger /path/to/node/with/trigger "/suite/task == complete" # return true if expression evaluates false otherwise - + --query state / # return top level state to standard out + --query state /path/to/node # return node state to standard out + --query dstate /path/to/node # state that can included suspended + --query repeat /path/to/node # return the current value as a string + --query repeat /path/to/node prev # return the previous value as a string + --query repeat /path/to/node next # return the next value as a string + --query event /path/to/task/with/event:event_name # return set | clear to standard out + --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out + --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out + --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out + --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out + --query variable /path/to/task/with/var:var_name # returns the variable value to standard out + --query variable /:var_name # returns the server variable value to standard out + --query trigger /path/to/node/with/trigger "/suite/task == complete" # return true if expression evaluates false otherwise The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/queue.rst b/docs/client_api/api/queue.rst index 0dd78d2f8..4891f3a72 100644 --- a/docs/client_api/api/queue.rst +++ b/docs/client_api/api/queue.rst @@ -53,7 +53,6 @@ The following help text is generated by :code:`ecflow_client --help=queue` trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed } - The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] diff --git a/docs/client_api/api/reloadcustompasswdfile.rst b/docs/client_api/api/reloadcustompasswdfile.rst index 9300b3769..5215b11d6 100644 --- a/docs/client_api/api/reloadcustompasswdfile.rst +++ b/docs/client_api/api/reloadcustompasswdfile.rst @@ -69,7 +69,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadcustom Usage: - --reloadcustompasswdfile + --reloadcustompasswdfile The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/reloadpasswdfile.rst b/docs/client_api/api/reloadpasswdfile.rst index 8f62a147d..da42b87d9 100644 --- a/docs/client_api/api/reloadpasswdfile.rst +++ b/docs/client_api/api/reloadpasswdfile.rst @@ -69,7 +69,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadpasswd Usage: - --reloadpasswdfile + --reloadpasswdfile The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/reloadwsfile.rst b/docs/client_api/api/reloadwsfile.rst index a2bc54443..920f6172e 100644 --- a/docs/client_api/api/reloadwsfile.rst +++ b/docs/client_api/api/reloadwsfile.rst @@ -61,7 +61,7 @@ The following help text is generated by :code:`ecflow_client --help=reloadwsfile Usage: - --reloadwsfile + --reloadwsfile The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/replace.rst b/docs/client_api/api/replace.rst index 2b2f0cb6b..dc38b4858 100644 --- a/docs/client_api/api/replace.rst +++ b/docs/client_api/api/replace.rst @@ -47,8 +47,8 @@ The following help text is generated by :code:`ecflow_client --help=replace` Usage: - --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1 - --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted + --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1 + --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/requeue.rst b/docs/client_api/api/requeue.rst index ef5a6663c..dd7ce0633 100644 --- a/docs/client_api/api/requeue.rst +++ b/docs/client_api/api/requeue.rst @@ -33,9 +33,9 @@ The following help text is generated by :code:`ecflow_client --help=requeue` Usage: - --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1 - --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies. - --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2' + --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1 + --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies. + --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2' The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/restore.rst b/docs/client_api/api/restore.rst index 51e9fc9d8..9c2a25117 100644 --- a/docs/client_api/api/restore.rst +++ b/docs/client_api/api/restore.rst @@ -48,8 +48,8 @@ The following help text is generated by :code:`ecflow_client --help=restore` Usage: - --restore=/s1/f1 # restore family /s1/f1 - --restore=/s1 /s2 # restore suites /s1 and /s2 + --restore=/s1/f1 # restore family /s1/f1 + --restore=/s1 /s2 # restore suites /s1 and /s2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/resume.rst b/docs/client_api/api/resume.rst index 8707d725f..76e675638 100644 --- a/docs/client_api/api/resume.rst +++ b/docs/client_api/api/resume.rst @@ -25,9 +25,8 @@ The following help text is generated by :code:`ecflow_client --help=resume` Usage: - --resume=/s1/f1/t1 # resume task s1/f1/t1 - --resume=/s1 /s2 # resume suites /s1 and /s2 - + --resume=/s1/f1/t1 # resume task s1/f1/t1 + --resume=/s1 /s2 # resume suites /s1 and /s2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/run.rst b/docs/client_api/api/run.rst index a4e56b887..725ef05aa 100644 --- a/docs/client_api/api/run.rst +++ b/docs/client_api/api/run.rst @@ -36,14 +36,20 @@ The following help text is generated by :code:`ecflow_client --help=run` arg2 = node path(s). The paths must begin with a leading '/' character. If the path is /suite/family will recursively run all tasks When providing multiple paths avoid running the same task twice - Example: + + Usage: + --run=/suite/t1 # run task t1 + Effect: + task t1; time 12:00 # will complete if run manually task t2; time 10:00 13:00 01:00 # will run 4 times before completing - When we have a time range(i.e as shown with task t2), then next time slot - is incremented for each run, until it expires, and the task completes. - Use the Why command, to show next run time (i.e. next time slot) + + Specifying a time range, as shown with task t2, means the next time slot + is incremented for each run, until it expires, and the task completes. + + Use the Why command, to show next run time (i.e. next time slot) The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/server_load.rst b/docs/client_api/api/server_load.rst index f2e16cbf7..3c74eee03 100644 --- a/docs/client_api/api/server_load.rst +++ b/docs/client_api/api/server_load.rst @@ -25,10 +25,11 @@ The following help text is generated by :code:`ecflow_client --help=server_load` This is done by parsing the log file. If no log file is provided, then the log file path is obtained from the server. If the returned log file path is not accessible an error is returned - This command produces a three files in the CWD. - o ..gnuplot.dat - o ..gnuplot.script - o ..png + This command produces a three files in the CWD: + + - ..gnuplot.dat + - ..gnuplot.script + - ..png The generated script can be manually changed, to see different rendering effects. i.e. just run 'gnuplot ..gnuplot.script' @@ -40,10 +41,10 @@ The following help text is generated by :code:`ecflow_client --help=server_load` Usage: - --server_load=/path/to_log_file # Parses log and generate gnuplot files - --server_load # Log file path is requested from server - # which is then used to generate gnuplot files - # *AVOID* if log file path is accessible + --server_load=/path/to_log_file # Parses log and generate gnuplot files + --server_load # Log file path is requested from server + # which is then used to generate gnuplot files + # *AVOID* if log file path is accessible Now use any png viewer to see the output i.e @@ -53,7 +54,6 @@ The following help text is generated by :code:`ecflow_client --help=server_load` > xdg-open ..png > w3m ..png - The client considers, for both user and task commands, the following environment variables: ECF_HOST [mandatory*] diff --git a/docs/client_api/api/server_version.rst b/docs/client_api/api/server_version.rst index b6b656280..0dc001003 100644 --- a/docs/client_api/api/server_version.rst +++ b/docs/client_api/api/server_version.rst @@ -25,9 +25,8 @@ The following help text is generated by :code:`ecflow_client --help=server_versi Usage: - --server_version - Writes the version to standard output - + --server_version + Writes the version to standard output The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/shutdown.rst b/docs/client_api/api/shutdown.rst index 6bf100188..6f6b38b19 100644 --- a/docs/client_api/api/shutdown.rst +++ b/docs/client_api/api/shutdown.rst @@ -23,7 +23,11 @@ The following help text is generated by :code:`ecflow_client --help=shutdown` Stop server from scheduling new jobs. arg1 = yes(optional) # use to bypass confirmation prompt,i.e - --shutdown=yes + + Usage: + + --shutdown=yes + The following table shows server behaviour in the different states. |----------------------------------------------------------------------------------| | Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing | diff --git a/docs/client_api/api/status.rst b/docs/client_api/api/status.rst index c41c0cdc4..de191660d 100644 --- a/docs/client_api/api/status.rst +++ b/docs/client_api/api/status.rst @@ -38,8 +38,8 @@ The following help text is generated by :code:`ecflow_client --help=status` Usage: - --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat - --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file + --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat + --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/suspend.rst b/docs/client_api/api/suspend.rst index c1f8cf2c5..590411997 100644 --- a/docs/client_api/api/suspend.rst +++ b/docs/client_api/api/suspend.rst @@ -25,9 +25,8 @@ The following help text is generated by :code:`ecflow_client --help=suspend` Usage: - --suspend=/s1/f1/t1 # suspend task s1/f1/t1 - --suspend=/s1 /s2 # suspend suites /s1 and /s2 - + --suspend=/s1/f1/t1 # suspend task s1/f1/t1 + --suspend=/s1 /s2 # suspend suites /s1 and /s2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/terminate.rst b/docs/client_api/api/terminate.rst index eabee5eca..820215e0f 100644 --- a/docs/client_api/api/terminate.rst +++ b/docs/client_api/api/terminate.rst @@ -23,7 +23,10 @@ The following help text is generated by :code:`ecflow_client --help=terminate` Terminate the server. arg1 = yes(optional) # use to bypass confirmation prompt.i.e - --terminate=yes + + Usage: + + --terminate=yes The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/wait.rst b/docs/client_api/api/wait.rst index 25ffd8a11..bd79926ee 100644 --- a/docs/client_api/api/wait.rst +++ b/docs/client_api/api/wait.rst @@ -27,7 +27,7 @@ The following help text is generated by :code:`ecflow_client --help=wait` Usage: - ecflow_client --wait="/suite/taskx == complete" + --wait="/suite/taskx == complete" The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/why.rst b/docs/client_api/api/why.rst index 03dc55e64..23c1fb882 100644 --- a/docs/client_api/api/why.rst +++ b/docs/client_api/api/why.rst @@ -31,8 +31,8 @@ The following help text is generated by :code:`ecflow_client --help=why` Usage: - --group="get; why" # returns why for all holding nodes - --group="get; why=/suite/family" # returns why for a specific node + --group="get; why" # returns why for all holding nodes + --group="get; why=/suite/family" # returns why for a specific node The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/zombie_adopt.rst b/docs/client_api/api/zombie_adopt.rst index 581a4731f..9329f1005 100644 --- a/docs/client_api/api/zombie_adopt.rst +++ b/docs/client_api/api/zombie_adopt.rst @@ -26,7 +26,10 @@ The following help text is generated by :code:`ecflow_client --help=zombie_adopt This is only allowed if the process id matches, otherwise an error is issued. The zombie reference stored in the server is then deleted. args = list of task paths, at least one expected - --zombie_adopt=/path/to/task /path/to/task2 + + Usage: + + --zombie_adopt=/path/to/task /path/to/task2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/zombie_block.rst b/docs/client_api/api/zombie_block.rst index 00fcf1c94..59a2055dd 100644 --- a/docs/client_api/api/zombie_block.rst +++ b/docs/client_api/api/zombie_block.rst @@ -27,7 +27,10 @@ The following help text is generated by :code:`ecflow_client --help=zombie_block attempting to connect to the server for 24 hours, and will then return an error. The connection timeout can be configured with environment ECF_TIMEOUT args = list of task paths, at least one expected - --zombie_block=/path/to/task /path/to/task2 + + Usage: + + --zombie_block=/path/to/task /path/to/task2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/zombie_fail.rst b/docs/client_api/api/zombie_fail.rst index cb096bfb3..b3e4eae8e 100644 --- a/docs/client_api/api/zombie_fail.rst +++ b/docs/client_api/api/zombie_fail.rst @@ -28,7 +28,10 @@ The following help text is generated by :code:`ecflow_client --help=zombie_fail` infinite recursion. The references to the zombie in the server is automatically deleted after 1 hour args = list of task paths, at least one expected - --zombie_fail=/path/to/task /path/to/task2 + + Usage: + + --zombie_fail=/path/to/task /path/to/task2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/zombie_fob.rst b/docs/client_api/api/zombie_fob.rst index 7174f9081..b855ae14f 100644 --- a/docs/client_api/api/zombie_fob.rst +++ b/docs/client_api/api/zombie_fob.rst @@ -28,7 +28,10 @@ The following help text is generated by :code:`ecflow_client --help=zombie_fob` allowing the job to finish. The references to the zombie in the server is automatically deleted after 1 hour args = list of task paths, at least one expected - --zombie_fob=/path/to/task1 /path/to/task2 + + Usage: + + --zombie_fob=/path/to/task1 /path/to/task2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/zombie_kill.rst b/docs/client_api/api/zombie_kill.rst index 821651787..711c13863 100644 --- a/docs/client_api/api/zombie_kill.rst +++ b/docs/client_api/api/zombie_kill.rst @@ -27,7 +27,10 @@ The following help text is generated by :code:`ecflow_client --help=zombie_kill` Can only kill zombies that have an associated Task, hence path zombies must be killed manually. arg = list of task paths, at least one expected - --zombie_kill=/path/to/task /path/to/task2 + + Usage: + + --zombie_kill=/path/to/task /path/to/task2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/zombie_remove.rst b/docs/client_api/api/zombie_remove.rst index 3b5db111f..c7f95d2e6 100644 --- a/docs/client_api/api/zombie_remove.rst +++ b/docs/client_api/api/zombie_remove.rst @@ -25,7 +25,10 @@ The following help text is generated by :code:`ecflow_client --help=zombie_remov Since a job typically has many child commands (i.e init, complete, event, meter, label, wait, queue) the zombie may reappear args = list of task paths, at least one expected - --zombie_remove=/path/to/task /path/to/task2 + + Usage: + + --zombie_remove=/path/to/task /path/to/task2 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/help.json b/docs/client_api/help.json index 437e88c6a..c8f30a2ed 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -1,11 +1,26 @@ { "schema_version": 1, "topics": [ - { "name": "all", "summary": "List all commands, verbosely" }, - { "name": "summary", "summary": "One line summary of all commands" }, - { "name": "task", "summary": "One line summary of task commands" }, - { "name": "user", "summary": "One line summary of user command" }, - { "name": "option", "summary": "One line summary of options" } + { + "name": "all", + "summary": "List all commands, verbosely" + }, + { + "name": "summary", + "summary": "One line summary of all commands" + }, + { + "name": "task", + "summary": "One line summary of task commands" + }, + { + "name": "user", + "summary": "One line summary of user command" + }, + { + "name": "option", + "summary": "One line summary of options" + } ], "commands": [ { @@ -26,7 +41,7 @@ "", "Usage:", "", - " ecflow_client --abort=reasonX" + " --abort=reasonX" ], "arguments": [ { @@ -35,8 +50,7 @@ "optional": true, "description": "Optionally provide a reason why the abort was raised" } - ], - "usage": ["ecflow_client --abort=reasonX"] + ] }, { "name": "alter", @@ -109,46 +123,45 @@ "", "Usage:", "", - " ecflow_client --alter=add variable \"value\" / # add server variable", - " ecflow_client --alter=add variable \"value\" /path/to/node # add node variable", + " --alter=add variable \"value\" / # add server variable", + " --alter=add variable \"value\" /path/to/node # add node variable", "", - " ecflow_client --alter=add time \"+00:20\" /path/to/node", + " --alter=add time \"+00:20\" /path/to/node", "", - " ecflow_client --alter=add date \"01.*.*\" /path/to/node", + " --alter=add date \"01.*.*\" /path/to/node", "", - " ecflow_client --alter=add day \"sunday\" /path/to/node", + " --alter=add day \"sunday\" /path/to/node", "", - " ecflow_client --alter=add label \"label_value\" /path/to/node", + " --alter=add label \"label_value\" /path/to/node", "", - " ecflow_client --alter=add event \"set\"|\"clear\" /path/to/node", + " --alter=add event \"set\"|\"clear\" /path/to/node", "", - " ecflow_client --alter=add meter \",,value\" /path/to/node", + " --alter=add meter \",,value\" /path/to/node", "", - " ecflow_client --alter=add late \"-s 00:01 -a 14:30 -c +00:01\" /path/to/node", + " --alter=add late \"-s 00:01 -a 14:30 -c +00:01\" /path/to/node", "", - " ecflow_client --alter=add limit mars \"100\" /path/to/node", + " --alter=add limit mars \"100\" /path/to/node", "", - " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"10\" /path/to/node", + " --alter=add inlimit /path/to/node/withlimit:limit_name \"10\" /path/to/node", "", - " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-s 10\" /path/to/node", + " --alter=add inlimit /path/to/node/withlimit:limit_name \"-s 10\" /path/to/node", "", - " ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name \"-n 10\" /path/to/node", + " --alter=add inlimit /path/to/node/withlimit:limit_name \"-n 10\" /path/to/node", "", - " # zombie attributes have the following structure:", - " `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time`", - " zombie_type = \"user\" | \"ecf\" | \"path\" | \"ecf_pid\" | \"ecf_passwd\" | \"ecf_pid_passwd\"", - " client_side_action = \"fob\" | \"fail\" | \"block\"", - " server_side_action = \"adopt\" | \"delete\" | \"kill\"", - " child = \"init\" | \"event\" | \"meter\" | \"label\" | \"wait\" | \"abort\" | \"complete\" | \"queue\"", - " zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60", + " # zombie attributes have the following structure:", + " `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time`", + " zombie_type = \"user\" | \"ecf\" | \"path\" | \"ecf_pid\" | \"ecf_passwd\" | \"ecf_pid_passwd\"", + " client_side_action = \"fob\" | \"fail\" | \"block\"", + " server_side_action = \"adopt\" | \"delete\" | \"kill\"", + " child = \"init\" | \"event\" | \"meter\" | \"label\" | \"wait\" | \"abort\" | \"complete\" | \"queue\"", + " zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60", "", - " ecflow_client --alter=add zombie \"ecf:fail::\" /path/to/node # ask system zombies to fail", - " ecflow_client --alter=add zombie \"user:fail::\" /path/to/node # ask user generated zombies to fail", - " ecflow_client --alter=add zombie \"path:fail::\" /path/to/node # ask path zombies to fail", + " --alter=add zombie \"ecf:fail::\" /path/to/node # ask system zombies to fail", + " --alter=add zombie \"user:fail::\" /path/to/node # ask user generated zombies to fail", + " --alter=add zombie \"path:fail::\" /path/to/node # ask path zombies to fail", "", - " ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED", - " ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode", - "" + " --alter=delete variable FRED /path/to/node # delete variable FRED", + " --alter=delete variable /path/to/node # delete *ALL* variables on the given snode" ] }, { @@ -192,9 +205,9 @@ "", "Usage:", "", - " --archive=/s1 # archive suite s1", - " --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2", - " --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" + " --archive=/s1 # archive suite s1", + " --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2", + " --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks" ] }, { @@ -214,10 +227,10 @@ "", "Usage:", "", - "--begin # will begin all suites", - "--begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted", - "--begin=\"mySuite\" # begin playing suite of name 'mySuite'", - "--begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check" + " --begin # will begin all suites", + " --begin=\"--force\" # reset and then begin all suites, bypassing any checks. Note: string must be quoted", + " --begin=\"mySuite\" # begin playing suite of name 'mySuite'", + " --begin=\"mySuite --force\" # reset and begin playing suite 'mySuite', bypass check" ] }, { @@ -233,7 +246,7 @@ "", "Usage:", "", - " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10", + " --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10", "An error is returned if the handle had not previously been registered", "The handle is created with --ch_register command", "To list all suites and handles use --ch_suites" @@ -252,8 +265,8 @@ "", "Usage:", "", - " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it", - " --ch_auto_add=10 false # modify handle 10 so that no new suites are added", + " --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it", + " --ch_auto_add=10 false # modify handle 10 so that no new suites are added", "The handle is created with --ch_register command", "To list all suites and handles use --ch_suites" ] @@ -271,7 +284,7 @@ "", "Usage:", "", - " --ch_drop=10 # drop the client handle 10", + " --ch_drop=10 # drop the client handle 10", "An error is returned if the handle had not previously been registered", "The handle stored on the local client is set to zero", "To list all suites and handles use --ch_suites" @@ -291,8 +304,8 @@ "", "Usage:", "", - " --ch_drop_user=ma0 # drop all handles associated with user ma0", - " --ch_drop_user # drop all handles associated with current user", + " --ch_drop_user=ma0 # drop all handles associated with user ma0", + " --ch_drop_user # drop all handles associated with current user", "An error is returned if no registered handles", "To list all suites and handles use --ch_suites" ] @@ -317,11 +330,12 @@ "", "Usage:", "", - " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites", - " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only", - " --ch_register=false # register handle, suites will be added later on", - " --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites", - " # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first", + " --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites", + " --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only", + " --ch_register=false # register handle, suites will be added later on", + " --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites", + " # The client handle as the first argument is typically used by GUI/python", + " # When the client handle is no zero, then it is dropped first", "To list all suites and handles use --ch_suites" ] }, @@ -338,8 +352,10 @@ "", "Usage:", "", - " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10", + " --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10", + "", "The handle is created with --ch_register command", + "", "To list all suites and handles use --ch_suites" ] }, @@ -366,9 +382,9 @@ "", "Usage:", "", - " --check=_all_ # Checks all the suites", - " --check=/ # Checks all the suites", - " --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" + " --check=_all_ # Checks all the suites", + " --check=/ # Checks all the suites", + " --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1" ] }, { @@ -413,19 +429,19 @@ "", "Usage:", "", - " --check_pt", - " Immediately check point the definition held in the server", - " --check_pt=never", - " Switch off check pointing", - " --check_pt=on_time", - " Start automatic check pointing at the interval stored in the server", - " --check_pt=180", - " Change the check pt interval to 180 seconds", - " --check_pt=on_time:90", - " Change mode and interval, to automatic check pointing every 90 seconds", - " --check_pt=alarm:35", - " Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds", - " set the late flag on the server." + " --check_pt", + " Immediately check point the definition held in the server", + " --check_pt=never", + " Switch off check pointing", + " --check_pt=on_time", + " Start automatic check pointing at the interval stored in the server", + " --check_pt=180", + " Change the check pt interval to 180 seconds", + " --check_pt=on_time:90", + " Change mode and interval, to automatic check pointing every 90 seconds", + " --check_pt=alarm:35", + " Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds", + " set the late flag on the server." ] }, { @@ -447,8 +463,8 @@ "", "Usage:", "", - " ecflow_client --complete", - " ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" + " --complete", + " --complete --remove name1 name2 # delete variables name1 and name2 on the task" ], "arguments": [ { @@ -456,10 +472,6 @@ "optional": true, "description": "a list of variables to removed from this task" } - ], - "usage": [ - "ecflow_client --complete", - "ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task" ] }, { @@ -493,10 +505,10 @@ "", "Usage:", "", - " --delete=_all_ # Delete all suites in server. Use with care.", - " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt", - " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted", - " --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt" + " --delete=_all_ # Delete all suites in server. Use with care.", + " --delete=/suite/f1/t1 # Delete node at /suite/f1/t1. This will prompt", + " --delete=force /suite/f1/t1 # Delete node at /suite/f1/t1 even if active or submitted", + " --delete=force yes /s1 /s2 # Delete suites s1,s2 even if active or submitted, bypassing prompt" ] }, { @@ -511,9 +523,8 @@ "", "Usage:", "", - " --edit_history=/s1/f1/t1 # return history of changes for the given node", - " --edit_history=clear # clear/purge *ALL* edit history from all nodes.", - "" + " --edit_history=/s1/f1/t1 # return history of changes for the given node", + " --edit_history=clear # clear/purge *ALL* edit history from all nodes." ] }, { @@ -549,31 +560,31 @@ "", "Usage:", "", - "--edit_script=/path/to/task edit > script_file", - " server returns script with the used variables to standard out", - " The user can choose to edit this file", + " --edit_script=/path/to/task edit > script_file", + " server returns script with the used variables to standard out", + " The user can choose to edit this file", "", - "--edit_script=/path/to/task pre_process > pre_processed_script_file", - " server will pre process the ecf file accessible from the server", - " (i.e expand all %includes) and return the file to standard out", + " --edit_script=/path/to/task pre_process > pre_processed_script_file", + " server will pre process the ecf file accessible from the server", + " (i.e expand all %includes) and return the file to standard out", "", - "--edit_script=/path/to/task submit script_file", - " Will extract the used variables in the 'script_file' and will uses these", - " variables during variable substitution of the ecf file accessible by the", - " server. This is then submitted as a job", + " --edit_script=/path/to/task submit script_file", + " Will extract the used variables in the 'script_file' and will uses these", + " variables during variable substitution of the ecf file accessible by the", + " server. This is then submitted as a job", "", - "--edit_script=/path/to/task pre_process_file file_to_pre_process", - " The server will pre-process the user supplied file and return the contents", - " to standard out. This pre-processing is the same as job file processing,", - " but on a arbitrary file", + " --edit_script=/path/to/task pre_process_file file_to_pre_process", + " The server will pre-process the user supplied file and return the contents", + " to standard out. This pre-processing is the same as job file processing,", + " but on a arbitrary file", "", - "--edit_script=/path/to/task submit_file file_to_submit", - " Will extract the used variables in the 'file_to_submit' and will uses these", - " variables during variable substitution, the file is then submitted for job", - " generation by the server", + " --edit_script=/path/to/task submit_file file_to_submit", + " Will extract the used variables in the 'file_to_submit' and will uses these", + " variables during variable substitution, the file is then submitted for job", + " generation by the server", "", - "--edit_script=/path/to/task submit_file file_to_submit create_alias", - " Like the the previous example but will create and run as an alias" + " --edit_script=/path/to/task submit_file file_to_submit create_alias", + " Like the the previous example but will create and run as an alias" ] }, { @@ -595,10 +606,9 @@ "", "Usage:", "", - " ecflow_client --event=ev # set the event, default since event initial value is clear", - " ecflow_client --event=ev set # set the event, explicit", - " ecflow_client --event=ev clear # clear the event, use when event initial value is set", - "" + " --event=ev # set the event, default since event initial value is clear", + " --event=ev set # set the event, explicit", + " --event=ev clear # clear the event, use when event initial value is set" ], "arguments": [ { @@ -611,11 +621,6 @@ "type": "string", "optional": true } - ], - "usage": [ - "ecflow_client --event=ev # set the event, default since event initial value is clear", - "ecflow_client --event=ev set # set the event, explicit", - "ecflow_client --event=ev clear # clear the event, use when event initial value is set" ] }, { @@ -659,19 +664,22 @@ "", "Usage:", "", - " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete", - " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task", - " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1", + " --force=complete /suite/t1 /suite/t2 # Set task t1 & t2 to complete", + " --force=clear /suite/task:ev # Clear the event 'ev' on task /suite/task", + " --force=complete recursive /suite/f1 # Recursively set complete all children of /suite/f1", + "", "Effect:", - " Consider the effect of forcing complete when the current time is at 09:00", - " suite s1", - " task t1; time 12:00 # will complete straight away", - " task t2; time 10:00 13:00 01:00 # will complete on fourth attempt", "", - " --force=complete /s1/t1 /s1/t2", - " When we have a time range(i.e as shown with task t2), it is re-queued and the", - " next time slot is incremented for each complete, until it expires, and the task completes.", - " Use the Why command, to show next run time (i.e. next time slot)" + " Consider the effect of applying `--force=complete /s1/t1 /s1/t2` at 09:00", + "", + " suite s1", + " task t1; time 12:00 # will complete straight away", + " task t2; time 10:00 13:00 01:00 # will complete on fourth attempt", + "", + " Specifying a time range, as shown with task t2, means the task is re-queued and the", + " next time slot is incremented for each complete, until it expires, and the task completes.", + "", + " Use the Why command, to show next run time (i.e. next time slot)" ] }, { @@ -703,9 +711,9 @@ "", "Usage:", "", - " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2", - " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1", - " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1" + " --free-dep=/s1/t1 /s2/t2 # free trigger dependencies for task's t1,t2", + " --free-dep=all /s1/f1/t1 # free all dependencies of /s1/f1/t1", + " --free-dep=date /s1/f1 # free holding date dependencies of /s1/f1" ] }, { @@ -722,8 +730,8 @@ "", "Usage:", "", - " --get # gets the definition from the server,and writes to standard out", - " --get=/s1 # gets the suite from the server,and writes to standard out" + " --get # gets the definition from the server,and writes to standard out", + " --get=/s1 # gets the suite from the server,and writes to standard out" ] }, { @@ -740,8 +748,8 @@ "", "Usage:", "", - " --get_state # gets the definition from the server,and writes to standard out", - " --get_state=/s1 # gets the suite from the server,and writes to standard out" + " --get_state # gets the definition from the server,and writes to standard out", + " --get_state=/s1 # gets the suite from the server,and writes to standard out" ] }, { @@ -758,11 +766,15 @@ "", "Usage:", "", - " --group=\"halt=yes; reloadwsfile; restart;\"", - " # halt server,bypass the confirmation prompt,", - " # reload white list file, restart server", - " --group=\"get; show\" # get server defs, and write to standard output", - " --group=\"get=/s1; show state\" # get suite 's1', and write state to standard output" + " --group=\"halt=yes; reloadwsfile; restart;\"", + " # halt server,bypass the confirmation prompt,", + " # reload white list file, restart server", + "", + " --group=\"get; show\"", + " # get server defs, and write to standard output", + "", + " --group=\"get=/s1; show state\"", + " # get suite 's1', and write state to standard output" ] }, { @@ -775,7 +787,11 @@ "Stop server communication with jobs, and new job scheduling.", "Also stops automatic check pointing", " arg1 = yes(optional) # use to bypass confirmation prompt,i.e.", - " --halt=yes", + "", + "Usage:", + "", + " --halt=yes", + "", "The following table shows server behaviour in the different states.", "|----------------------------------------------------------------------------------|", "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |", @@ -805,8 +821,8 @@ "", "Usage:", "", - " ecflow_client --init=$$", - " ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" + " --init=$$", + " --init=$$ --add name=value name2=value2 # add/update variables to task" ], "arguments": [ { @@ -820,10 +836,6 @@ "optional": true, "description": "add/update variables as name value pairs" } - ], - "usage": [ - "ecflow_client --init=$$", - "ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task" ] }, { @@ -857,8 +869,8 @@ "", "Usage:", "", - " --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2", - " --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1" + " --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2", + " --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1" ] }, { @@ -880,7 +892,7 @@ "", "Usage:", "", - " ecflow_client --label=progressed merlin" + " --label=progressed merlin" ], "arguments": [ { @@ -892,8 +904,7 @@ "optional": false, "description": "The labels values can be single or multi-line(space separated quoted strings)" } - ], - "usage": ["ecflow_client --label=progressed merlin"] + ] }, { "name": "load", @@ -914,13 +925,12 @@ "", "Usage:", "", - "--load=/my/home/exotic.def # will error if suites of same name exists", - "--load=/my/home/exotic.def force # overwrite suite's of same name in the server", - "--load=/my/home/exotic.def check_only # Just check, don't send to server", - "--load=/my/home/exotic.def stats # Show defs statistics, don't send to server", - "--load=host1.3141.check # Load checkpoint file to the server", - "--load=host1.3141.check print # print definition to standard out in defs format", - "" + " --load=/my/home/exotic.def # will error if suites of same name exists", + " --load=/my/home/exotic.def force # overwrite suite's of same name in the server", + " --load=/my/home/exotic.def check_only # Just check, don't send to server", + " --load=/my/home/exotic.def stats # Show defs statistics, don't send to server", + " --load=host1.3141.check # Load checkpoint file to the server", + " --load=host1.3141.check print # print definition to standard out in defs format" ] }, { @@ -955,13 +965,12 @@ "", "Usage:", "", - " --log=get # Write the last 100 lines of the log file to standard out", - " --log=get 200 # Write the last 200 lines of the log file to standard out", - " --log=clear # Clear the log file. The log is now empty", - " --log=flush # Flush and close log file, next request will re-open log file", - " --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG", - " --log=new # Close and flush log file, and create a new log file using ECF_LOG variable", - "" + " --log=get # Write the last 100 lines of the log file to standard out", + " --log=get 200 # Write the last 200 lines of the log file to standard out", + " --log=clear # Clear the log file. The log is now empty", + " --log=flush # Flush and close log file, next request will re-open log file", + " --log=new /path/to/new/log/file # Close and flush log file, and create a new log file, updates ECF_LOG", + " --log=new # Close and flush log file, and create a new log file using ECF_LOG variable" ] }, { @@ -982,7 +991,7 @@ "", "Usage:", "", - " ecflow_client --meter=my_meter 20" + " --meter=my_meter 20" ], "arguments": [ { @@ -995,8 +1004,7 @@ "type": "int", "optional": false } - ], - "usage": ["ecflow_client --meter=my_meter 20"] + ] }, { "name": "migrate", @@ -1022,8 +1030,7 @@ "Usage:", "", " --migrate # show all suites", - " --migrate=/s1 # show state for suite s1", - "" + " --migrate=/s1 # show state for suite s1" ] }, { @@ -1046,7 +1053,7 @@ "", "Usage:", "", - " --msg=\"place me in the log file\"" + " --msg=\"place me in the log file\"" ] }, { @@ -1094,7 +1101,7 @@ "", "Usage:", "", - " --order=/suite/f1 top # move node f1 to the top" + " --order=/suite/f1 top # move node f1 to the top" ] }, { @@ -1108,11 +1115,11 @@ "", "Usage:", "", - " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144", - " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,", - " # otherwise default port of 3141", - " --ping # Check if server alive by using environment variables", - " # ECF_HOST and ECF_PORT", + " --ping --host=mach --port=3144 # Check if server alive on host mach & port 3144", + " --ping --host=fred # Check if server alive on host fred and port ECF_PORT,", + " # otherwise default port of 3141", + " --ping # Check if server alive by using environment variables", + " # ECF_HOST and ECF_PORT", "If ECF_HOST not defined uses 'localhost', if ECF_PORT not defined assumes 3141" ] }, @@ -1139,7 +1146,7 @@ "", "Usage:", "", - " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)" + " --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141)" ] }, { @@ -1183,21 +1190,20 @@ "", "Usage:", "", - " ecflow_client --query state / # return top level state to standard out", - " ecflow_client --query state /path/to/node # return node state to standard out", - " ecflow_client --query dstate /path/to/node # state that can included suspended", - " ecflow_client --query repeat /path/to/node # return the current value as a string", - " ecflow_client --query repeat /path/to/node prev # return the previous value as a string", - " ecflow_client --query repeat /path/to/node next # return the next value as a string", - " ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out", - " ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out", - " ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out", - " ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out", - " ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out", - " ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to standard out", - " ecflow_client --query variable /:var_name # returns the server variable value to standard out", - " ecflow_client --query trigger /path/to/node/with/trigger \"/suite/task == complete\" # return true if expression evaluates false otherwise", - "" + " --query state / # return top level state to standard out", + " --query state /path/to/node # return node state to standard out", + " --query dstate /path/to/node # state that can included suspended", + " --query repeat /path/to/node # return the current value as a string", + " --query repeat /path/to/node prev # return the previous value as a string", + " --query repeat /path/to/node next # return the next value as a string", + " --query event /path/to/task/with/event:event_name # return set | clear to standard out", + " --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out", + " --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out", + " --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out", + " --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out", + " --query variable /path/to/task/with/var:var_name # returns the variable value to standard out", + " --query variable /:var_name # returns the server variable value to standard out", + " --query trigger /path/to/node/with/trigger \"/suite/task == complete\" # return true if expression evaluates false otherwise" ] }, { @@ -1237,8 +1243,7 @@ " ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed", "done", "", - "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }", - "" + "trap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" ], "arguments": [ { @@ -1264,9 +1269,6 @@ "optional": true, "description": "(optional). The path where the queue is defined.\nBy default we search for the queue up the node tree." } - ], - "usage": [ - "step=\"\"\nQNAME=\"my_queue_name\"\nwhile [1 == 1 ] ; do\n # this return the first queued/aborted step, then increments to next step, return when all steps processed\n step=$(ecflow_client --queue=$QNAME active) # of the form string i.e \"003\". this step is now active\n if [[ $step == \"\" ]] ; then\n break;\n fi\n ...\n ecflow_client --queue=$QNAME complete $step # tell ecflow this step completed\ndone\n\ntrap() { ecflow_client --queue=$QNAME aborted $step # tell ecflow this step failed }" ] }, { @@ -1324,7 +1326,7 @@ "", "Usage:", "", - " --reloadcustompasswdfile" + " --reloadcustompasswdfile" ] }, { @@ -1382,7 +1384,7 @@ "", "Usage:", "", - " --reloadpasswdfile" + " --reloadpasswdfile" ] }, { @@ -1432,7 +1434,7 @@ "", "Usage:", "", - " --reloadwsfile" + " --reloadwsfile" ] }, { @@ -1468,8 +1470,8 @@ "", "Usage:", "", - " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1", - " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted" + " --replace=/suite/f1/t1 /tmp/client.def parent # Add/replace node tree /suite/f1/t1", + " --replace=/suite/f1/t1 /tmp/client.def false force # replace t1 even if its active or submitted" ] }, { @@ -1491,9 +1493,9 @@ "", "Usage:", "", - " --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1", - " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.", - " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'" + " --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1", + " --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies.", + " --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2'" ] }, { @@ -1548,8 +1550,8 @@ "", "Usage:", "", - " --restore=/s1/f1 # restore family /s1/f1", - " --restore=/s1 /s2 # restore suites /s1 and /s2" + " --restore=/s1/f1 # restore family /s1/f1", + " --restore=/s1 /s2 # restore suites /s1 and /s2" ] }, { @@ -1575,9 +1577,8 @@ "", "Usage:", "", - " --resume=/s1/f1/t1 # resume task s1/f1/t1", - " --resume=/s1 /s2 # resume suites /s1 and /s2", - "" + " --resume=/s1/f1/t1 # resume task s1/f1/t1", + " --resume=/s1 /s2 # resume suites /s1 and /s2" ] }, { @@ -1602,14 +1603,20 @@ " arg2 = node path(s). The paths must begin with a leading '/' character.", " If the path is /suite/family will recursively run all tasks", " When providing multiple paths avoid running the same task twice", - "Example:", + "", + "Usage:", + "", " --run=/suite/t1 # run task t1", + "", "Effect:", + "", " task t1; time 12:00 # will complete if run manually", " task t2; time 10:00 13:00 01:00 # will run 4 times before completing", - " When we have a time range(i.e as shown with task t2), then next time slot", - " is incremented for each run, until it expires, and the task completes.", - " Use the Why command, to show next run time (i.e. next time slot)" + "", + " Specifying a time range, as shown with task t2, means the next time slot", + " is incremented for each run, until it expires, and the task completes.", + "", + " Use the Why command, to show next run time (i.e. next time slot)" ] }, { @@ -1623,10 +1630,11 @@ "This is done by parsing the log file. If no log file is provided,", "then the log file path is obtained from the server. If the returned", "log file path is not accessible an error is returned", - "This command produces a three files in the CWD.", - " o ..gnuplot.dat", - " o ..gnuplot.script", - " o ..png", + "This command produces a three files in the CWD:", + "", + " - ..gnuplot.dat", + " - ..gnuplot.script", + " - ..png", "", "The generated script can be manually changed, to see different rendering", "effects. i.e. just run 'gnuplot ..gnuplot.script'", @@ -1638,10 +1646,10 @@ "", "Usage:", "", - " --server_load=/path/to_log_file # Parses log and generate gnuplot files", - " --server_load # Log file path is requested from server", - " # which is then used to generate gnuplot files", - " # *AVOID* if log file path is accessible", + " --server_load=/path/to_log_file # Parses log and generate gnuplot files", + " --server_load # Log file path is requested from server", + " # which is then used to generate gnuplot files", + " # *AVOID* if log file path is accessible", "", "Now use any png viewer to see the output i.e", "", @@ -1649,8 +1657,7 @@ "> feh ..png", "> eog ..png", "> xdg-open ..png", - "> w3m ..png", - "" + "> w3m ..png" ] }, { @@ -1664,9 +1671,8 @@ "", "Usage:", "", - " --server_version", - " Writes the version to standard output", - "" + " --server_version", + " Writes the version to standard output" ] }, { @@ -1721,7 +1727,11 @@ "description": [ "Stop server from scheduling new jobs.", " arg1 = yes(optional) # use to bypass confirmation prompt,i.e", - " --shutdown=yes", + "", + "Usage:", + "", + " --shutdown=yes", + "", "The following table shows server behaviour in the different states.", "|----------------------------------------------------------------------------------|", "| Server State | User Request | Task Request |Job Scheduling | Auto-Check-pointing |", @@ -1780,8 +1790,8 @@ "", "Usage:", "", - " --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat", - " --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" + " --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat", + " --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file" ] }, { @@ -1803,9 +1813,8 @@ "", "Usage:", "", - " --suspend=/s1/f1/t1 # suspend task s1/f1/t1", - " --suspend=/s1 /s2 # suspend suites /s1 and /s2", - "" + " --suspend=/s1/f1/t1 # suspend task s1/f1/t1", + " --suspend=/s1 /s2 # suspend suites /s1 and /s2" ] }, { @@ -1860,7 +1869,10 @@ "description": [ "Terminate the server.", " arg1 = yes(optional) # use to bypass confirmation prompt.i.e", - " --terminate=yes" + "", + "Usage:", + "", + " --terminate=yes" ] }, { @@ -1876,7 +1888,7 @@ "", "Usage:", "", - " ecflow_client --wait=\"/suite/taskx == complete\"" + " --wait=\"/suite/taskx == complete\"" ], "arguments": [ { @@ -1884,8 +1896,7 @@ "type": "string", "optional": false } - ], - "usage": ["ecflow_client --wait=\"/suite/taskx == complete\""] + ] }, { "name": "why", @@ -1904,8 +1915,8 @@ "", "Usage:", "", - " --group=\"get; why\" # returns why for all holding nodes", - " --group=\"get; why=/suite/family\" # returns why for a specific node" + " --group=\"get; why\" # returns why for all holding nodes", + " --group=\"get; why=/suite/family\" # returns why for a specific node" ] }, { @@ -1931,7 +1942,10 @@ "This is only allowed if the process id matches, otherwise an error is issued.", "The zombie reference stored in the server is then deleted.", " args = list of task paths, at least one expected", - " --zombie_adopt=/path/to/task /path/to/task2" + "", + "Usage:", + "", + " --zombie_adopt=/path/to/task /path/to/task2" ] }, { @@ -1947,7 +1961,10 @@ "attempting to connect to the server for 24 hours, and will then return an error.", "The connection timeout can be configured with environment ECF_TIMEOUT", " args = list of task paths, at least one expected", - " --zombie_block=/path/to/task /path/to/task2" + "", + "Usage:", + "", + " --zombie_block=/path/to/task /path/to/task2" ] }, { @@ -1964,7 +1981,10 @@ "infinite recursion.", "The references to the zombie in the server is automatically deleted after 1 hour", " args = list of task paths, at least one expected", - " --zombie_fail=/path/to/task /path/to/task2" + "", + "Usage:", + "", + " --zombie_fail=/path/to/task /path/to/task2" ] }, { @@ -1981,7 +2001,10 @@ "allowing the job to finish.", "The references to the zombie in the server is automatically deleted after 1 hour", " args = list of task paths, at least one expected", - " --zombie_fob=/path/to/task1 /path/to/task2" + "", + "Usage:", + "", + " --zombie_fob=/path/to/task1 /path/to/task2" ] }, { @@ -1997,7 +2020,10 @@ "Can only kill zombies that have an associated Task, hence path zombies", "must be killed manually.", " arg = list of task paths, at least one expected", - " --zombie_kill=/path/to/task /path/to/task2" + "", + "Usage:", + "", + " --zombie_kill=/path/to/task /path/to/task2" ] }, { @@ -2011,7 +2037,10 @@ "Since a job typically has many child commands (i.e init, complete, event, meter, label, wait, queue)", "the zombie may reappear", " args = list of task paths, at least one expected", - " --zombie_remove=/path/to/task /path/to/task2" + "", + "Usage:", + "", + " --zombie_remove=/path/to/task /path/to/task2" ] } ], @@ -2062,19 +2091,13 @@ "name": "http", "kind": "global-option", "summary": "Enables communication over HTTP between client/server.", - "description": [ - "Enables communication over HTTP between client/server.", - "" - ] + "description": ["Enables communication over HTTP between client/server."] }, { "name": "https", "kind": "global-option", "summary": "Enables communication over HTTPS between client/server.", - "description": [ - "Enables communication over HTTPS between client/server.", - "" - ] + "description": ["Enables communication over HTTPS between client/server."] }, { "name": "help", diff --git a/docs/client_api/help.schema.json b/docs/client_api/help.schema.json index 4d4936edb..d470ad7ac 100644 --- a/docs/client_api/help.schema.json +++ b/docs/client_api/help.schema.json @@ -76,12 +76,6 @@ "arguments": { "type": "array", "items": { "$ref": "#/$defs/argument" } - }, - "usage": { - "description": "Absent when the source has no documented invocation example (e.g. no 'Usage:' text in desc()).", - "type": "array", - "items": { "type": "string", "minLength": 1 }, - "minItems": 1 } } }, From ca60ba516fbe5291b4254c9108a0e53e569979c1 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 07:26:41 +0100 Subject: [PATCH 47/49] Auto-generate command_internals Help tabs from help.json command_internals.rst is hand-maintained, but its per-command "Help" tab reproduces the ecflow_client --help text, which drifted from the manifest (stale "child command" wording, old Usage format). Add update_internal.py to regenerate that text in place from help.json and hook it into the documentation build after build.py. The update is content-only: it rewrites the code-block bodies and the HTML selector panels, leaving the surrounding prose, tables, panel order/ids, and the other tabs untouched. Refresh all 33 Help tabs. --- docs/CMakeLists.txt | 4 + docs/client_api/command_internals.rst | 542 ++++++++++++++++---------- docs/client_api/update_internal.py | 169 ++++++++ 3 files changed, 505 insertions(+), 210 deletions(-) create mode 100755 docs/client_api/update_internal.py diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 9d4ef82ba..d274da861 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -55,6 +55,8 @@ add_custom_command( ${CMAKE_COMMAND} -E rm -rf ${CMAKE_CURRENT_SOURCE_DIR}/client_api/api/* COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/client_api/build.py + COMMAND + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/update_internal.py COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/client_api/api @@ -75,6 +77,8 @@ add_custom_command( USES_TERMINAL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/client_api/build.py + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/update_internal.py + ${CMAKE_CURRENT_SOURCE_DIR}/client_api/command_internals.rst ${CMAKE_CURRENT_SOURCE_DIR}/client_api/help.json ${CMAKE_CURRENT_SOURCE_DIR}/client_api/help.schema.json ${CMAKE_CURRENT_SOURCE_DIR}/client_api/validate_help_manifest.py diff --git a/docs/client_api/command_internals.rst b/docs/client_api/command_internals.rst index ee2496427..5886b77f7 100644 --- a/docs/client_api/command_internals.rst +++ b/docs/client_api/command_internals.rst @@ -259,12 +259,13 @@ The zombie handling is the same as for ``InitCmd``. arg1 = (optional) string(reason) Optionally provide a reason why the abort was raised - If this child command is a zombie, then the default action will be to *block*. + If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. Otherwise the blocking period is defined by ECF_TIMEOUT. Usage: - ecflow_client --abort=reasonX + + --abort=reasonX .. tab:: Request @@ -373,7 +374,7 @@ variables as the job finishes. The zombie handling is the same as for ``InitCmd` Mark task as complete. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - If this child command is a zombie, then the default action will be to *block*. + If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. Otherwise the blocking period is defined by ECF_TIMEOUT. The init command allows variables to be added, and complete command @@ -381,8 +382,9 @@ variables as the job finishes. The zombie handling is the same as for ``InitCmd` arg1(--remove)(optional) = a list of variables to removed from this task Usage: - ecflow_client --complete - ecflow_client --complete --remove name1 name2 # delete variables name1 and name2 on the task + + --complete + --complete --remove name1 name2 # delete variables name1 and name2 on the task .. tab:: Request @@ -520,7 +522,8 @@ synchronisation on the state of other nodes. arg1 = string(expression) Usage: - ecflow_client --wait="/suite/taskx == complete" + + --wait="/suite/taskx == complete" .. tab:: Request @@ -653,14 +656,15 @@ complete without error); this can be overridden with zombie attributes. arg2(string)(optional) = [ set | clear] default value is set - If this child command is a zombie, then the default action will be to *fob*, + If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error The default can be overridden by using zombie attributes. Usage: - ecflow_client --event=ev # set the event, default since event initial value is clear - ecflow_client --event=ev set # set the event, explicit - ecflow_client --event=ev clear # clear the event, use when event initial value is set + + --event=ev # set the event, default since event initial value is clear + --event=ev set # set the event, explicit + --event=ev clear # clear the event, use when event initial value is set .. tab:: Request @@ -806,13 +810,14 @@ zombie attributes, and the blocking period is bounded by ``ECF_TIMEOUT``. Using remote id allows the jobs to be killed arg2(--add)(optional)= add/update variables as name value pairs - If this child command is a zombie, then the default action will be to *block*. + If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. Otherwise the blocking period is defined by ECF_TIMEOUT. Usage: - ecflow_client --init=$$ - ecflow_client --init=$$ --add name=value name2=value2 # add/update variables to task + + --init=$$ + --init=$$ --add name=value name2=value2 # add/update variables to task .. tab:: Request @@ -957,12 +962,13 @@ zombie action is to *fob*. arg2 = The new label value The labels values can be single or multi-line(space separated quoted strings) - If this child command is a zombie, then the default action will be to *fob*, + If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error The default can be overridden by using zombie attributes. Usage: - ecflow_client --label=progressed merlin + + --label=progressed merlin .. tab:: Request @@ -1069,12 +1075,13 @@ zombie action is to *fob*. arg1(string) = meter-name arg2(int) = the new meter value - If this child command is a zombie, then the default action will be to *fob*, + If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error The default can be overridden by using zombie attributes. Usage: - ecflow_client --meter=my_meter 20 + + --meter=my_meter 20 .. tab:: Request @@ -1200,11 +1207,12 @@ The ``active`` and ``no_of_aborted`` actions return a string; the others return arg4(string) = path: (optional). The path where the queue is defined. By default we search for the queue up the node tree. - If this child command is a zombie, then the default action will be to *block*, + If this task command is a zombie, then the default action will be to *block*, The default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will search for the queue up the node hierarchy. If no queue found, command fails Usage: + step="" QNAME="my_queue_name" while [1 == 1 ] ; do @@ -1561,45 +1569,45 @@ carried by ``flag_type_``, and ``flag_`` selects set (``true``) versus clear (`` Usage: - ecflow_client --alter=add variable "value" / # add server variable - ecflow_client --alter=add variable "value" /path/to/node # add node variable + --alter=add variable "value" / # add server variable + --alter=add variable "value" /path/to/node # add node variable - ecflow_client --alter=add time "+00:20" /path/to/node + --alter=add time "+00:20" /path/to/node - ecflow_client --alter=add date "01.*.*" /path/to/node + --alter=add date "01.*.*" /path/to/node - ecflow_client --alter=add day "sunday" /path/to/node + --alter=add day "sunday" /path/to/node - ecflow_client --alter=add label "label_value" /path/to/node + --alter=add label "label_value" /path/to/node - ecflow_client --alter=add event "set"|"clear" /path/to/node + --alter=add event "set"|"clear" /path/to/node - ecflow_client --alter=add meter ",,value" /path/to/node + --alter=add meter ",,value" /path/to/node - ecflow_client --alter=add late "-s 00:01 -a 14:30 -c +00:01" /path/to/node + --alter=add late "-s 00:01 -a 14:30 -c +00:01" /path/to/node - ecflow_client --alter=add limit mars "100" /path/to/node + --alter=add limit mars "100" /path/to/node - ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name "10" /path/to/node + --alter=add inlimit /path/to/node/withlimit:limit_name "10" /path/to/node - ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name "-s 10" /path/to/node + --alter=add inlimit /path/to/node/withlimit:limit_name "-s 10" /path/to/node - ecflow_client --alter=add inlimit /path/to/node/withlimit:limit_name "-n 10" /path/to/node + --alter=add inlimit /path/to/node/withlimit:limit_name "-n 10" /path/to/node - # zombie attributes have the following structure: - `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time` - zombie_type = "user" | "ecf" | "path" | "ecf_pid" | "ecf_passwd" | "ecf_pid_passwd" - client_side_action = "fob" | "fail" | "block" - server_side_action = "adopt" | "delete" | "kill" - child = "init" | "event" | "meter" | "label" | "wait" | "abort" | "complete" | "queue" - zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60 + # zombie attributes have the following structure: + `zombie_type`:(`client_side_action` | `server_side_action`):`child`:`zombie_life_time` + zombie_type = "user" | "ecf" | "path" | "ecf_pid" | "ecf_passwd" | "ecf_pid_passwd" + client_side_action = "fob" | "fail" | "block" + server_side_action = "adopt" | "delete" | "kill" + child = "init" | "event" | "meter" | "label" | "wait" | "abort" | "complete" | "queue" + zombie_life_time = unsigned integer default: user(300), ecf(3600), path(900) minimum is 60 - ecflow_client --alter=add zombie "ecf:fail::" /path/to/node # ask system zombies to fail - ecflow_client --alter=add zombie "user:fail::" /path/to/node # ask user generated zombies to fail - ecflow_client --alter=add zombie "path:fail::" /path/to/node # ask path zombies to fail + --alter=add zombie "ecf:fail::" /path/to/node # ask system zombies to fail + --alter=add zombie "user:fail::" /path/to/node # ask user generated zombies to fail + --alter=add zombie "path:fail::" /path/to/node # ask path zombies to fail - ecflow_client --alter=delete variable FRED /path/to/node # delete variable FRED - ecflow_client --alter=delete variable /path/to/node # delete *ALL* variables on the given snode + --alter=delete variable FRED /path/to/node # delete variable FRED + --alter=delete variable /path/to/node # delete *ALL* variables on the given snode .. tab:: Request @@ -1859,11 +1867,13 @@ starts. The ``force`` flag is stored in ``force_``; the request below is for ``- force means reset the begin status on the suites and bypass checks. This is only required if suite-name is provide as the first argument Using force can cause the creation of zombies + Usage: - --begin # will begin all suites - --begin="--force" # reset and then begin all suites, bypassing any checks. Note: string must be quoted - --begin="mySuite" # begin playing suite of name 'mySuite' - --begin="mySuite --force" # reset and begin playing suite 'mySuite', bypass check + + --begin # will begin all suites + --begin="--force" # reset and then begin all suites, bypassing any checks. Note: string must be quoted + --begin="mySuite" # begin playing suite of name 'mySuite' + --begin="mySuite --force" # reset and begin playing suite 'mySuite', bypass check .. tab:: Request @@ -2089,20 +2099,22 @@ save-time alarm. Called with no argument it checkpoints immediately. : This specifies the interval in seconds when server should automatically check pt. This will only take effect of mode is on_time/CHECK_ON_TIME Should ideally be a value greater than 60 seconds, default is 120 seconds + Usage: - --check_pt - Immediately check point the definition held in the server - --check_pt=never - Switch off check pointing - --check_pt=on_time - Start automatic check pointing at the interval stored in the server - --check_pt=180 - Change the check pt interval to 180 seconds - --check_pt=on_time:90 - Change mode and interval, to automatic check pointing every 90 seconds - --check_pt=alarm:35 - Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds - set the late flag on the server. + + --check_pt + Immediately check point the definition held in the server + --check_pt=never + Switch off check pointing + --check_pt=on_time + Start automatic check pointing at the interval stored in the server + --check_pt=180 + Change the check pt interval to 180 seconds + --check_pt=on_time:90 + Change mode and interval, to automatic check pointing every 90 seconds + --check_pt=alarm:35 + Change the alarm time for check pt saves. i.e if saving the check pt takes longer than 35 seconds + set the late flag on the server. .. tab:: Request @@ -2261,12 +2273,15 @@ track a chosen subset of suites and receive only their changes. The operation is This command affects news() and sync() commands arg1 = true | false # true means add new suites to my list, when they are created arg2 = names # should be a list of suite names, names not in the definition are ignored + Usage: - --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites - --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only - --ch_register=false # register handle, suites will be added later on - --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites - # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first + + --ch_register=true s1 s2 s3 # register interest in suites s1,s2,s3 and any new suites + --ch_register=false s1 s2 s3 # register interest in suites s1,s2,s3 only + --ch_register=false # register handle, suites will be added later on + --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites + # The client handle as the first argument is typically used by GUI/python + # When the client handle is no zero, then it is dropped first To list all suites and handles use --ch_suites @@ -2286,9 +2303,11 @@ track a chosen subset of suites and receive only their changes. The operation is If no user provided will drop for current user. Client must ensure un-used handle are dropped otherwise they will stay, in the server. arg1 = user # The user to be drooped, if left empty drop current user + Usage: - --ch_drop_user=ma0 # drop all handles associated with user ma0 - --ch_drop_user # drop all handles associated with current user + + --ch_drop_user=ma0 # drop all handles associated with user ma0 + --ch_drop_user # drop all handles associated with current user An error is returned if no registered handles To list all suites and handles use --ch_suites @@ -2308,9 +2329,13 @@ track a chosen subset of suites and receive only their changes. The operation is Remove a set of suites, from an existing handle. arg1 = handle(integer) # The handle must be an integer that is > 0 arg2 = names # should be a list of suite names, names not in the definition are ignored + Usage: - --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10 + + --ch_rem=10 s2 s3 s4 # remove suites s2 s3,s4 from handle 10 + The handle is created with --ch_register command + To list all suites and handles use --ch_suites + + Usage: + + --terminate=yes + + --reloadwsfile + + --reloadpasswdfile + + --reloadcustompasswdfile .. tab:: Request @@ -3181,9 +3225,11 @@ target by ``absNodePath_``: Get all suite node tree's from the server and write to standard out. The output is parse-able, and can be used to re-load the definition arg = NULL | arg = node path + Usage: - --get # gets the definition from the server,and writes to standard out - --get=/s1 # gets the suite from the server,and writes to standard out + + --get # gets the definition from the server,and writes to standard out + --get=/s1 # gets the suite from the server,and writes to standard out + + --group="get; why" # returns why for all holding nodes + --group="get; why=/suite/family" # returns why for a specific node + + --get_state # gets the definition from the server,and writes to standard out + --get_state=/s1 # gets the suite from the server,and writes to standard out + + Usage: + + --suspend=/s1/f1/t1 # suspend task s1/f1/t1 + --suspend=/s1 /s2 # suspend suites /s1 and /s2 + + Usage: + + --resume=/s1/f1/t1 # resume task s1/f1/t1 + --resume=/s1 /s2 # resume suites /s1 and /s2 + + Usage: + + --kill=/s1/f1/t1 /s1/f2/t2 # kill the jobs for tasks t1 and t2 + --file=/s1/f1/t1 kill # write to standard out the '.kill' file for task /s1/f1/t1 + + Usage: + + --status=/s1/f1/t1 # ECF_STATUS_CMD should output to %ECF_JOB%.stat + --file=/s1/f1/t1 stat # Return contents of %ECF_JOB%.stat file + + --check=_all_ # Checks all the suites + --check=/ # Checks all the suites + --check=/s1 /s2/f1/t1 # Check suite /s1 and task t1 + + Usage: + + --edit_history=/s1/f1/t1 # return history of changes for the given node + --edit_history=clear # clear/purge *ALL* edit history from all nodes. + Usage: + + --archive=/s1 # archive suite s1 + --archive=/s1/f1 /s2 # archive family /s1/f1 and suite /s2 + --archive=force /s1 /s2 # archive suites /s1,/s2 even if they have active tasks + + Usage: + + --restore=/s1/f1 # restore family /s1/f1 + --restore=/s1 /s2 # restore suites /s1 and /s2 .. tab:: Request @@ -4828,8 +4919,10 @@ Moves a node subtree to a new parent, possibly on a different server. Internally then the source node must correspond to a suite. - If the source node is added as a child, then its name must be unique amongst its peers + Usage: - --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141) + + --plug=/suite macX:3141 # move the suite to ecFlow server on host(macX) and port(3141) .. tab:: Request @@ -4964,20 +5057,21 @@ inside scripts to branch on a node's state. arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat Usage: - ecflow_client --query state / # return top level state to standard out - ecflow_client --query state /path/to/node # return node state to standard out - ecflow_client --query dstate /path/to/node # state that can included suspended - ecflow_client --query repeat /path/to/node # return the current value as a string - ecflow_client --query repeat /path/to/node prev # return the previous value as a string - ecflow_client --query repeat /path/to/node next # return the next value as a string - ecflow_client --query event /path/to/task/with/event:event_name # return set | clear to standard out - ecflow_client --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out - ecflow_client --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out - ecflow_client --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out - ecflow_client --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out - ecflow_client --query variable /path/to/task/with/var:var_name # returns the variable value to standard out - ecflow_client --query variable /:var_name # returns the server variable value to standard out - ecflow_client --query trigger /path/to/node/with/trigger "/suite/task == complete" # return true if expression evaluates false otherwise + + --query state / # return top level state to standard out + --query state /path/to/node # return node state to standard out + --query dstate /path/to/node # state that can included suspended + --query repeat /path/to/node # return the current value as a string + --query repeat /path/to/node prev # return the previous value as a string + --query repeat /path/to/node next # return the next value as a string + --query event /path/to/task/with/event:event_name # return set | clear to standard out + --query meter /path/to/task/with/meter:meter_name # returns the current value of the meter to standard out + --query limit /path/to/task/with/limit:limit_name # returns the current value of the limit to standard out + --query limit_max /path/to/task/with/limit:limit_name # returns the max value of the limit to standard out + --query label /path/to/task/with/label:label_name # returns the current value of the label to standard out + --query variable /path/to/task/with/var:var_name # returns the variable value to standard out + --query variable /:var_name # returns the server variable value to standard out + --query trigger /path/to/node/with/trigger "/suite/task == complete" # return true if expression evaluates false otherwise .. tab:: Request @@ -5183,9 +5277,10 @@ Requeues nodes so that they may run again. ``option_`` encodes the modifier (``0 arg2 = list of node paths. The node paths must begin with a leading '/' character Usage: - --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1 - --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies. - --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2' + + --requeue=abort /suite/f1 # re-queue all aborted tasks of /suite/f1 + --requeue=force /suite/f1 # forcibly re-queue /suite/f1 and all its children.May cause zombies. + --requeue=/s1/f1/t1 /s1/t2 # Re-queue node '/suite/f1/t1' and '/s1/t2' .. tab:: Request @@ -5297,14 +5392,20 @@ ignored. arg2 = node path(s). The paths must begin with a leading '/' character. If the path is /suite/family will recursively run all tasks When providing multiple paths avoid running the same task twice - Example: + + Usage: + --run=/suite/t1 # run task t1 + Effect: + task t1; time 12:00 # will complete if run manually task t2; time 10:00 13:00 01:00 # will run 4 times before completing - When we have a time range(i.e as shown with task t2), then next time slot - is incremented for each run, until it expires, and the task completes. - Use the Why command, to show next run time (i.e. next time slot) + + Specifying a time range, as shown with task t2, means the next time slot + is incremented for each run, until it expires, and the task completes. + + Use the Why command, to show next run time (i.e. next time slot) .. tab:: Request @@ -5400,9 +5501,11 @@ payload holds only the base-class ``cl_host_`` and ``user_``. -------------- Returns the version number of the server + Usage: - --server_version - Writes the version to standard output + + --server_version + Writes the version to standard output .. tab:: Request @@ -5525,6 +5628,7 @@ not part of the serialized payload, so the request carries only the base-class ` trigger AST No Yes No Usage: + --group="get ; show" --group="get ; show defs" # same as the previous example --group="get ; show state" # Show all state for the node tree @@ -5668,7 +5772,10 @@ carried by ``user_action_``: allowing the job to finish. The references to the zombie in the server is automatically deleted after 1 hour args = list of task paths, at least one expected - --zombie_fob=/path/to/task1 /path/to/task2 + + Usage: + + --zombie_fob=/path/to/task1 /path/to/task2 + + Usage: + + --zombie_fail=/path/to/task /path/to/task2 + + Usage: + + --zombie_adopt=/path/to/task /path/to/task2 + + Usage: + + --zombie_remove=/path/to/task /path/to/task2 + + Usage: + + --zombie_block=/path/to/task /path/to/task2 + + Usage: + + --zombie_kill=/path/to/task /path/to/task2 .. tab:: Request diff --git a/docs/client_api/update_internal.py b/docs/client_api/update_internal.py new file mode 100755 index 000000000..ee1eaa5ee --- /dev/null +++ b/docs/client_api/update_internal.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +""" +Refresh the ``Help`` blocks in command_internals.rst from help.json. + +``command_internals.rst`` is a hand-maintained developer reference. + +Each per-command section carries a ``.. tab:: Help`` block that reproduces the +``ecflow_client --help=`` text (without the common environment-variable +footer). That text is the one part that must stay in step with the help manifest; +this script rewrites it in place from docs/client_api/help.json, leaving the +surrounding prose, tables and the other tabs (Usage, Request, Reply) untouched. + +The update is content-only and markup-driven: command names are read from the +existing markup (the code-block's first line, or the panel ids of the HTML +selector), and only the rendered help text is replaced. Adding or removing a +command from a selector remains a manual edit. + +Two Help-block shapes are handled: + + * single-command sections use a ``.. code-block:: none`` block; + * multi-command sections use a ``.. raw:: html`` selector with one ``
``
+   panel per action.
+"""
+import html
+import pathlib
+import re
+import sys
+
+HERE = pathlib.Path(__file__).resolve().parent
+sys.path.insert(0, str(HERE))
+
+from build import join_description, load_manifest  # noqa: E402
+
+RST = HERE / "command_internals.rst"
+BODY_INDENT = " " * 12  # indentation of code-block / raw-html content
+
+
+def help_text(command):
+    """Render the ``--help=`` body: name banner plus the joined description."""
+    name = command["name"]
+    return f"{name}\n{'-' * len(name)}\n\n{join_description(command['description'])}"
+
+
+def render_code_block(command):
+    """Return the code-block body lines (single-command Help tab), indented for the source."""
+    return [BODY_INDENT + line if line else "" for line in help_text(command).split("\n")]
+
+
+def render_pre(open_tag, command):
+    """Return the ``
`` panel lines (multi-command Help tab), HTML-escaped and indented.
+
+    @param open_tag The verbatim ``            
`` opening (indent included).
+    """
+    escaped = html.escape(help_text(command), quote=True).split("\n")
+    lines = [open_tag + escaped[0]]
+    for line in escaped[1:-1]:
+        lines.append(BODY_INDENT + line if line else "")
+    last = escaped[-1]
+    lines.append((BODY_INDENT + last if last else "") + "
") + return lines + + +def indent_of(line): + return len(line) - len(line.lstrip(" ")) + + +def replace_help_block(lines, start, commands): + """Rewrite the Help tab that begins at ``lines[start]`` (``.. tab:: Help``). + + @param commands Mapping of command name to its manifest entry. + @return The index one past the rewritten block (unchanged length otherwise). + """ + # The block runs until the next tab (``.. tab::`` at 4 spaces) or a dedent out of the tab. + end = start + 1 + while end < len(lines): + stripped = lines[end].strip() + if stripped.startswith(".. tab::") and indent_of(lines[end]) == 4: + break + if stripped and indent_of(lines[end]) < 4: + break + end += 1 + + block = lines[start:end] + + raw_at = next((i for i, l in enumerate(block) if l.strip() == ".. raw:: html"), None) + code_at = next((i for i, l in enumerate(block) if l.strip() == ".. code-block:: none"), None) + + if raw_at is not None: + new_block = _rewrite_raw_html(block, raw_at, commands) + elif code_at is not None: + new_block = _rewrite_code_block(block, code_at, commands) + else: + raise ValueError(f"Help tab at line {start + 1} has neither a code-block nor a raw-html body") + + lines[start:end] = new_block + return start + len(new_block) + + +def _lookup(commands, name, where): + command = commands.get(name) + if command is None: + raise KeyError(f"{where}: '{name}' is not a command in help.json") + return command + + +def _rewrite_code_block(block, code_at, commands): + # Body is everything after the code-block directive and its blank line. + body_start = code_at + 1 + while body_start < len(block) and block[body_start].strip() == "": + body_start += 1 + body_end = len(block) + while body_end > body_start and block[body_end - 1].strip() == "": + body_end -= 1 + + name = next((l.strip() for l in block[body_start:body_end] if l.strip()), None) + if name is None: + raise ValueError("empty code-block Help body") + command = _lookup(commands, name, "code-block Help") + + head = block[:code_at + 1] + [""] + tail = block[body_end:] # trailing blank line(s) before the next tab + return head + render_code_block(command) + tail + + +_PRE_OPEN = re.compile(r'^(\s*
]*>)(.*)$')
+
+
+def _rewrite_raw_html(block, raw_at, commands):
+    out = list(block[:raw_at + 1])
+    i = raw_at + 1
+    while i < len(block):
+        line = block[i]
+        m = _PRE_OPEN.match(line)
+        if not m:
+            out.append(line)
+            i += 1
+            continue
+        open_tag, first = m.group(1), m.group(2)
+        name = html.unescape(first).strip()
+        # consume the panel body up to and including the line closing 
+ j = i + while "
" not in block[j]: + j += 1 + command = _lookup(commands, name, "raw-html panel") + out.extend(render_pre(open_tag, command)) + i = j + 1 + return out + + +def main(): + manifest = load_manifest() + commands = {c["name"]: c for c in manifest["commands"]} + + lines = RST.read_text(encoding="utf-8").split("\n") + updated = 0 + i = 0 + while i < len(lines): + if lines[i].strip() == ".. tab:: Help": + i = replace_help_block(lines, i, commands) + updated += 1 + else: + i += 1 + + RST.write_text("\n".join(lines), encoding="utf-8") + print(f"{RST.name}: refreshed {updated} Help tab(s) from help.json") + + +if __name__ == "__main__": + main() From 09c72ea36742fc63d788c2ca56fa7f1642158370 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 07:51:39 +0100 Subject: [PATCH 48/49] Fix help manifest text deferred as future work Corrections preserved byte-for-byte during the manifest migration, now applied: - ECF_TRYNO: close the unmatched parenthesis. - ECF_DENIED: add the missing apostrophe ("ECF_TIMEOUT's wait"). - ECF_RID: set overridable_by "rid" so it renders [mandatory*], like the other CLI-overridable variables. - abort: use the usage placeholder instead of the "reasonX" typo. - queue: split the run-together "attributes.If the path" into two lines. Regenerate the CLI docs and the command_internals Help tabs. --- docs/client_api/api/abort.rst | 8 ++++---- docs/client_api/api/complete.rst | 6 +++--- docs/client_api/api/event.rst | 6 +++--- docs/client_api/api/init.rst | 6 +++--- docs/client_api/api/label.rst | 6 +++--- docs/client_api/api/meter.rst | 6 +++--- docs/client_api/api/queue.rst | 9 +++++---- docs/client_api/api/wait.rst | 6 +++--- docs/client_api/command_internals.rst | 7 ++++--- docs/client_api/help.json | 10 ++++++---- 10 files changed, 37 insertions(+), 33 deletions(-) diff --git a/docs/client_api/api/abort.rst b/docs/client_api/api/abort.rst index f7bfc2e52..01d978e78 100644 --- a/docs/client_api/api/abort.rst +++ b/docs/client_api/api/abort.rst @@ -32,7 +32,7 @@ The following help text is generated by :code:`ecflow_client --help=abort` Usage: - --abort=reasonX + --abort= The client considers, for both user and task commands, the following environment variables: @@ -58,13 +58,13 @@ The following help text is generated by :code:`ecflow_client --help=abort` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/complete.rst b/docs/client_api/api/complete.rst index 44c05c102..fea64be57 100644 --- a/docs/client_api/api/complete.rst +++ b/docs/client_api/api/complete.rst @@ -60,13 +60,13 @@ The following help text is generated by :code:`ecflow_client --help=complete` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/event.rst b/docs/client_api/api/event.rst index 83719a73c..cbef91277 100644 --- a/docs/client_api/api/event.rst +++ b/docs/client_api/api/event.rst @@ -61,13 +61,13 @@ The following help text is generated by :code:`ecflow_client --help=event` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/init.rst b/docs/client_api/api/init.rst index 891d6de6e..710577bc6 100644 --- a/docs/client_api/api/init.rst +++ b/docs/client_api/api/init.rst @@ -60,13 +60,13 @@ The following help text is generated by :code:`ecflow_client --help=init` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/label.rst b/docs/client_api/api/label.rst index 56ba375b1..2de660220 100644 --- a/docs/client_api/api/label.rst +++ b/docs/client_api/api/label.rst @@ -59,13 +59,13 @@ The following help text is generated by :code:`ecflow_client --help=label` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/meter.rst b/docs/client_api/api/meter.rst index 8fb7cf2e4..2f3ec10bb 100644 --- a/docs/client_api/api/meter.rst +++ b/docs/client_api/api/meter.rst @@ -58,13 +58,13 @@ The following help text is generated by :code:`ecflow_client --help=meter` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/queue.rst b/docs/client_api/api/queue.rst index 4891f3a72..45eeee6ec 100644 --- a/docs/client_api/api/queue.rst +++ b/docs/client_api/api/queue.rst @@ -34,7 +34,8 @@ The following help text is generated by :code:`ecflow_client --help=queue` By default we search for the queue up the node tree. If this task command is a zombie, then the default action will be to *block*, - The default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will + The default can be overridden by using zombie attributes. + If the path to the queue is not defined, then this command will search for the queue up the node hierarchy. If no queue found, command fails Usage: @@ -77,13 +78,13 @@ The following help text is generated by :code:`ecflow_client --help=queue` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/api/wait.rst b/docs/client_api/api/wait.rst index bd79926ee..97f59a76b 100644 --- a/docs/client_api/api/wait.rst +++ b/docs/client_api/api/wait.rst @@ -53,13 +53,13 @@ The following help text is generated by :code:`ecflow_client --help=wait` ECF_PASS [mandatory] The job password (defined by the server, and used to authenticate client requests) ECF_TRYNO [mandatory] - The run number of the job (defined by the server, and used in job/output file name generation. - ECF_RID [mandatory] + The run number of the job (defined by the server, and used in job/output file name generation). + ECF_RID [mandatory*] The process identifier. Supports identifying zombies and automated killing of running jobs ECF_TIMEOUT [optional] Maximum time in *seconds* for client to deliver message to main server; default is 24 hours ECF_DENIED [optional] - Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait. + Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait. NO_ECF [optional] If set, ecflow_client exits immediately with success; useful to test the scripts without a server diff --git a/docs/client_api/command_internals.rst b/docs/client_api/command_internals.rst index 5886b77f7..eaa0df6b4 100644 --- a/docs/client_api/command_internals.rst +++ b/docs/client_api/command_internals.rst @@ -240,7 +240,7 @@ The zombie handling is the same as for ``InitCmd``. .. code-block:: shell - ecflow_client --abort=reasonX + ecflow_client --abort= # a bare --abort is valid; the server substitutes a default reason ecflow_client --abort @@ -265,7 +265,7 @@ The zombie handling is the same as for ``InitCmd``. Usage: - --abort=reasonX + --abort= .. tab:: Request @@ -1208,7 +1208,8 @@ The ``active`` and ``no_of_aborted`` actions return a string; the others return By default we search for the queue up the node tree. If this task command is a zombie, then the default action will be to *block*, - The default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will + The default can be overridden by using zombie attributes. + If the path to the queue is not defined, then this command will search for the queue up the node hierarchy. If no queue found, command fails Usage: diff --git a/docs/client_api/help.json b/docs/client_api/help.json index c8f30a2ed..7795cdf8a 100644 --- a/docs/client_api/help.json +++ b/docs/client_api/help.json @@ -41,7 +41,7 @@ "", "Usage:", "", - " --abort=reasonX" + " --abort=" ], "arguments": [ { @@ -1226,7 +1226,8 @@ " By default we search for the queue up the node tree.", "", "If this task command is a zombie, then the default action will be to *block*,", - "The default can be overridden by using zombie attributes.If the path to the queue is not defined, then this command will", + "The default can be overridden by using zombie attributes.", + "If the path to the queue is not defined, then this command will", "search for the queue up the node hierarchy. If no queue found, command fails", "", "Usage:", @@ -2194,13 +2195,14 @@ "type": "int", "required": "mandatory", "applies_to": "task", - "description": "The run number of the job (defined by the server, and used in job/output file name generation." + "description": "The run number of the job (defined by the server, and used in job/output file name generation)." }, { "name": "ECF_RID", "type": "string", "required": "mandatory", "applies_to": "task", + "overridable_by": "rid", "description": "The process identifier. Supports identifying zombies and automated killing of running jobs" }, { @@ -2215,7 +2217,7 @@ "type": "any", "required": "optional", "applies_to": "task", - "description": "Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUTs wait." + "description": "Allows task to exit with an error, upon connection failure, thus avoids ECF_TIMEOUT's wait." }, { "name": "NO_ECF", From b2fc664cba411b03003888e699dc58da89f3bc87 Mon Sep 17 00:00:00 2001 From: Marcos Bento Date: Fri, 24 Jul 2026 09:24:27 +0100 Subject: [PATCH 49/49] Standardise argument listings across CLI help text Each command's inline "argN = ..." text used a different hand-written layout (type/name/description in different positions, some commands omitting a type or description entirely). Replace it with a uniform "Argument(s):" block for every command that documents arguments: one name per line, with "(optional)" and its type inlined, and a stacked "#"-prefixed description underneath. Applies to all 35 commands with argument text except alter, whose per-operation conditional argument shape is already tracked as separate future work and stays a single prose block for now. Regenerate the CLI docs and the command_internals Help tabs to match. --- docs/client_api/api/abort.rst | 7 +- docs/client_api/api/begin.rst | 12 +- docs/client_api/api/ch_add.rst | 12 +- docs/client_api/api/ch_auto_add.rst | 11 +- docs/client_api/api/ch_drop.rst | 9 +- docs/client_api/api/ch_drop_user.rst | 7 +- docs/client_api/api/ch_register.rst | 12 +- docs/client_api/api/ch_rem.rst | 11 +- docs/client_api/api/check_pt.rst | 22 +- docs/client_api/api/complete.rst | 6 +- docs/client_api/api/delete.rst | 16 +- docs/client_api/api/edit_script.rst | 59 ++- docs/client_api/api/event.rst | 9 +- docs/client_api/api/file.rst | 21 +- docs/client_api/api/force.rst | 22 +- docs/client_api/api/free-dep.rst | 23 +- docs/client_api/api/group.rst | 7 +- docs/client_api/api/halt.rst | 6 +- docs/client_api/api/init.rst | 13 +- docs/client_api/api/label.rst | 11 +- docs/client_api/api/load.rst | 10 +- docs/client_api/api/log.rst | 45 ++- docs/client_api/api/meter.rst | 10 +- docs/client_api/api/msg.rst | 6 +- docs/client_api/api/order.rst | 10 +- docs/client_api/api/plug.rst | 11 +- docs/client_api/api/query.rst | 16 +- docs/client_api/api/queue.rst | 28 +- docs/client_api/api/replace.rst | 30 +- docs/client_api/api/requeue.rst | 17 +- docs/client_api/api/run.rst | 18 +- docs/client_api/api/server_load.rst | 6 +- docs/client_api/api/show.rst | 36 +- docs/client_api/api/shutdown.rst | 6 +- docs/client_api/api/terminate.rst | 6 +- docs/client_api/api/wait.rst | 6 +- docs/client_api/cli_commands.rst | 2 +- docs/client_api/command_internals.rst | 527 +++++++++++++++++------- docs/client_api/help.json | 561 ++++++++++++++++++-------- 39 files changed, 1159 insertions(+), 488 deletions(-) diff --git a/docs/client_api/api/abort.rst b/docs/client_api/api/abort.rst index 01d978e78..9bc5ac74e 100644 --- a/docs/client_api/api/abort.rst +++ b/docs/client_api/api/abort.rst @@ -23,8 +23,11 @@ The following help text is generated by :code:`ecflow_client --help=abort` Mark task as aborted. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1 = (optional) string(reason) - Optionally provide a reason why the abort was raised + + Argument(s): + + reason: (optional) string + # Optionally provide a reason why the abort was raised If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. diff --git a/docs/client_api/api/begin.rst b/docs/client_api/api/begin.rst index d63523ab4..68f6b7ee5 100644 --- a/docs/client_api/api/begin.rst +++ b/docs/client_api/api/begin.rst @@ -23,11 +23,13 @@ The following help text is generated by :code:`ecflow_client --help=begin` Begin playing the definition in the server. Expects zero or a single quoted string. - arg1 = suite-name | Nothing | force - play the chosen suite, if no arg specified, play all suites, in the definition - force means reset the begin status on the suites and bypass checks. - This is only required if suite-name is provide as the first argument - Using force can cause the creation of zombies + + Argument(s): + + suite-name: (optional) + # The name of the selected suite; if not specified, means all suites. + # Including `--force` in the value means reset the begin status and bypass checks. + # Important: using `--force` might cause the appearance of zombies. Usage: diff --git a/docs/client_api/api/ch_add.rst b/docs/client_api/api/ch_add.rst index 818c072ee..2eaf25851 100644 --- a/docs/client_api/api/ch_add.rst +++ b/docs/client_api/api/ch_add.rst @@ -22,12 +22,20 @@ The following help text is generated by :code:`ecflow_client --help=ch_add` ------ Add a set of suites, to an existing handle. - arg1 = handle(integer) # The handle must be an integer that is > 0 - arg2 = names # should be a list of suite names, names not in the definition are ignored + + Argument(s): + + handle: integer + # The handle value (must be an integer > 0) + + names + # A space separated list of suite names. + # Note: names not in the definition are ignored. Usage: --ch_add=10 s2 s3 s4 # add suites s2 s3,s4 to handle 10 + An error is returned if the handle had not previously been registered The handle is created with --ch_register command To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_auto_add.rst b/docs/client_api/api/ch_auto_add.rst index f7a9674cc..cbf4c51f9 100644 --- a/docs/client_api/api/ch_auto_add.rst +++ b/docs/client_api/api/ch_auto_add.rst @@ -22,13 +22,20 @@ The following help text is generated by :code:`ecflow_client --help=ch_auto_add` ----------- Change an existing handle so that new suites can be added automatically. - arg1 = handle(integer) # The handle must be an integer that is > 0 - arg2 = true | false # true means add new suites to my list, when they are created + + Argument(s): + + handle: integer + # The handle value (must be an integer > 0) + + auto-add: true | false + # `true` means add new suites to my list, when they are created Usage: --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it --ch_auto_add=10 false # modify handle 10 so that no new suites are added + The handle is created with --ch_register command To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_drop.rst b/docs/client_api/api/ch_drop.rst index 8488b070f..2463d0804 100644 --- a/docs/client_api/api/ch_drop.rst +++ b/docs/client_api/api/ch_drop.rst @@ -23,12 +23,17 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop` Drop/de-register the client handle. Un-used handle should be dropped otherwise they will stay, in the server. - arg1 = handle(integer) # The handle must be an integer that is > 0 + + Argument(s): + + handle: integer + # The handle value (must be an integer > 0) Usage: --ch_drop=10 # drop the client handle 10 - An error is returned if the handle had not previously been registered + + An error is returned if the handle was not previously been registered. The handle stored on the local client is set to zero To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_drop_user.rst b/docs/client_api/api/ch_drop_user.rst index 0f9b7a78f..faae5dbef 100644 --- a/docs/client_api/api/ch_drop_user.rst +++ b/docs/client_api/api/ch_drop_user.rst @@ -24,12 +24,17 @@ The following help text is generated by :code:`ecflow_client --help=ch_drop_user Drop/de-register all handles associated with the given user. If no user provided will drop for current user. Client must ensure un-used handle are dropped otherwise they will stay, in the server. - arg1 = user # The user to be drooped, if left empty drop current user + + Argument(s): + + user + # The user to be dropped; if empty, means drop current user Usage: --ch_drop_user=ma0 # drop all handles associated with user ma0 --ch_drop_user # drop all handles associated with current user + An error is returned if no registered handles To list all suites and handles use --ch_suites diff --git a/docs/client_api/api/ch_register.rst b/docs/client_api/api/ch_register.rst index 1ae032d69..4bd1c68ba 100644 --- a/docs/client_api/api/ch_register.rst +++ b/docs/client_api/api/ch_register.rst @@ -29,8 +29,15 @@ The following help text is generated by :code:`ecflow_client --help=ch_register` Deleted suites will stay registered, and must be explicitly removed/dropped. Note: Suites can be registered before they are loaded into the server This command affects news() and sync() commands - arg1 = true | false # true means add new suites to my list, when they are created - arg2 = names # should be a list of suite names, names not in the definition are ignored + + Argument(s): + + auto-add: true | false + # `true` means add any new suites to user list, when they are created + + names + # A space separated list of suite names. + # Note: names not in the definition are ignored. Usage: @@ -40,6 +47,7 @@ The following help text is generated by :code:`ecflow_client --help=ch_register` --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first + To list all suites and handles use --ch_suites The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/ch_rem.rst b/docs/client_api/api/ch_rem.rst index dfd7e6fe6..49ccbc874 100644 --- a/docs/client_api/api/ch_rem.rst +++ b/docs/client_api/api/ch_rem.rst @@ -22,8 +22,15 @@ The following help text is generated by :code:`ecflow_client --help=ch_rem` ------ Remove a set of suites, from an existing handle. - arg1 = handle(integer) # The handle must be an integer that is > 0 - arg2 = names # should be a list of suite names, names not in the definition are ignored + + Argument(s): + + handle: integer + # The handle value (must be an integer > 0) + + names + # A space separated list of suite names. + # Note: names not in the definition are ignored. Usage: diff --git a/docs/client_api/api/check_pt.rst b/docs/client_api/api/check_pt.rst index cddd2acc4..a2d42d616 100644 --- a/docs/client_api/api/check_pt.rst +++ b/docs/client_api/api/check_pt.rst @@ -30,15 +30,19 @@ The following help text is generated by :code:`ecflow_client --help=check_pt` or by using --alter functionality Note excessive save times can interfere with job scheduling. The alarm threshold can be changed. See below. - arg1 = (optional) mode [ never | on_time | on_time: | always | ] - never : Never check point the definition in the server - on_time : Turn on automatic check pointing at interval stored on server - on_time : Turn on automatic check point, with the specified interval in seconds - alarm : Modify the alarm notification time for check pt saving to disk - always : Check point at any change in node tree, *NOT* recommended for large definitions - : This specifies the interval in seconds when server should automatically check pt. - This will only take effect of mode is on_time/CHECK_ON_TIME - Should ideally be a value greater than 60 seconds, default is 120 seconds + + Argument(s): + + mode: (optional) [ never | on_time | on_time: | always | ] + # never : Never check point the definition in the server + # on_time : Turn on automatic check pointing at interval stored on server + # on_time : Turn on automatic check point, with the specified interval in seconds + # alarm : Modify the alarm notification time for check pt saving to disk + # always : Check point at any change in node tree, *NOT* recommended for large definitions + # : This specifies the interval in seconds when server should automatically check pt. + # + # This only takes effect if mode is on_time/CHECK_ON_TIME + # The default value is 120 seconds, and should be greater than 60 seconds Usage: diff --git a/docs/client_api/api/complete.rst b/docs/client_api/api/complete.rst index fea64be57..64ed6d72a 100644 --- a/docs/client_api/api/complete.rst +++ b/docs/client_api/api/complete.rst @@ -29,7 +29,11 @@ The following help text is generated by :code:`ecflow_client --help=complete` Otherwise the blocking period is defined by ECF_TIMEOUT. The init command allows variables to be added, and complete command allows for them to be removed. - arg1(--remove)(optional) = a list of variables to removed from this task + + Argument(s): + + --remove: (optional) + # A list of space separated variables to removed from this task Usage: diff --git a/docs/client_api/api/delete.rst b/docs/client_api/api/delete.rst index 0755b1f38..3c02d0bdd 100644 --- a/docs/client_api/api/delete.rst +++ b/docs/client_api/api/delete.rst @@ -22,10 +22,18 @@ The following help text is generated by :code:`ecflow_client --help=delete` ------ Deletes the specified node(s) or _ALL_ existing definitions( i.e delete all suites) in the server. - arg1 = [ force | yes ](optional) # Use this parameter to bypass checks, i.e. for active or submitted tasks - arg2 = yes(optional) # Use 'yes' to bypass the confirmation prompt - arg3 = node paths | _all_ # _all_ means delete all suites - # node paths must start with a leading '/' + + Argument(s): + + force: (optional) [ force | yes ] + # Use this parameter to bypass checks, i.e. for active or submitted tasks + + confirm: (optional) + # value must be "yes"; bypasses the confirmation prompt + + target: node paths | _all_ + # The value `_all_` means delete all suites. + # The node paths must start with a leading '/'. Usage: diff --git a/docs/client_api/api/edit_script.rst b/docs/client_api/api/edit_script.rst index a21b58abf..7a2b3663d 100644 --- a/docs/client_api/api/edit_script.rst +++ b/docs/client_api/api/edit_script.rst @@ -23,27 +23,44 @@ The following help text is generated by :code:`ecflow_client --help=edit_script` Allows user to edit, pre-process and submit the script. Will allow pre-processing of arbitrary file with 'pre_process_file' option - arg1 = path to task # The path to the task/alias - arg2 = [ edit | pre_process | submit | pre_process_file | submit_file ] - edit : will return the script file to standard out. The script will - include used variables enclosed between %comment/%end at the - start of the file - pre_process: Will return the script file to standard out.The script will - include used variables enclosed between %comment/%end at the - start of the file and with all %include expanded - submit: Will extract the used variables from the supplied file, i.e - between the %comment/%end and use these them to generate the - job using the ecf file accessible from the server - pre_process_file: Will pre process the user supplied file. - Will expand includes,variable substitution, - remove manual & comment sections. - submit_file: Like submit, but the supplied file, is submitted by the server - The last 2 options allow complete freedom to debug the script file - arg3 = [ path_to_script_file ] - needed for option [ pre_process_file | submit_file ] - arg4 = create_alias (optional) default value is false, for use with 'submit_file' option - arg5 = no_run (optional) default value is false, i.e immediately run the alias - is no_run is specified the alias in only created + + Argument(s): + + path to task + # The path to the task/alias + + action: [ edit | pre_process | submit | pre_process_file | submit_file ] + # edit : Returns the script file to standard out. The script will + # include used variables enclosed between %comment/%end at the + # start of the file + # + # pre_process: Returns the script file to standard out. The script will + # include used variables enclosed between %comment/%end at the + # start of the file and with all %include expanded + # + # submit: Extracts the used variables from the supplied file, i.e + # between the %comment/%end and use these them to generate the + # job using the ecf file accessible from the server + # + # pre_process_file: Pre-process the user supplied file, + # expanding includes, performing variable substitution, + # removing manual & comment sections. + # + # submit_file: Like submit, but the supplied file is submitted by the server. + # + # Options `pre_process_file` and `submit_file` facilitate debugging the script file + + path_to_script_file: (optional) + # The path to the script file + # Required for options `pre_process_file` and `submit_file` + + create_alias: (optional) + # If specified, will create an alias for the task and submit the job using this alias + # Default value is false, to be used in combination with `submit_file` option + + no_run: (optional) + # If specified, will create an alias for the task but will not submit the job + # Default value is false, to be used in combination with `submit_file` option Usage: diff --git a/docs/client_api/api/event.rst b/docs/client_api/api/event.rst index cbef91277..b728672cb 100644 --- a/docs/client_api/api/event.rst +++ b/docs/client_api/api/event.rst @@ -23,9 +23,14 @@ The following help text is generated by :code:`ecflow_client --help=event` Change event. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1(string | int) = event-name - arg2(string)(optional) = [ set | clear] default value is set + Argument(s): + + event-name: string | int + # The name of the event to be set or cleared. + + state: (optional) string + # [ set | clear], default value is set If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error diff --git a/docs/client_api/api/file.rst b/docs/client_api/api/file.rst index ae9947b28..3ec44d430 100644 --- a/docs/client_api/api/file.rst +++ b/docs/client_api/api/file.rst @@ -23,11 +23,22 @@ The following help text is generated by :code:`ecflow_client --help=file` Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ] By default will return the script. - arg1 = path to node - arg2 = (optional) [ script | job | jobout | manual | kill | stat ] - kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill - stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat - arg3 = (optional) max_lines = 10000 + + Argument(s): + + path: + # The path to the node + + kind: (optional) [ script | job | jobout | manual | kill | stat ] + # `script`: returns the script file, e.g., %ECF_JOB%.ecf + # `job`: returns the pre-processed job script + # `jobout`: returns the job output/log, e.g., %ECF_JOB%.out + # `manual`: returns the job manual + # `kill`: returns the output of ECF_KILL_CMD, e.g., %ECF_JOB%.kill + # `stat`: returns the output of ECF_STATUS_CMD, e.g., %ECF_JOB%.stat + + max_lines: (optional) + # default is 10000 The client considers, for both user and task commands, the following environment variables: diff --git a/docs/client_api/api/force.rst b/docs/client_api/api/force.rst index 7db183582..d6ae7593e 100644 --- a/docs/client_api/api/force.rst +++ b/docs/client_api/api/force.rst @@ -29,13 +29,21 @@ The following help text is generated by :code:`ecflow_client --help=force` This behaviour allow Repeat values to be incremented interactively. A repeat attribute is incremented when all the child nodes are complete in this case the child nodes are automatically re-queued. - arg1 = [ unknown | complete | queued | submitted | active | aborted | clear | set ] - arg2 = (optional) recursive - Applies state to node and recursively to all its children - arg3 = (optional) full - Set repeat variables to last value, only works in conjunction - with recursive option - arg4 = path_to_node or path_to_node:: paths must begin with '/' + + Argument(s): + + state: [ unknown | complete | queued | submitted | active | aborted | clear | set ] + # The state to be set. If the state is either `set` or `clear`, then the event is updated. + + recursive: (optional) + # Applies state to node, and recursively to all its children + + full: (optional) + # Set repeat variables to last value, only works in conjunction + # with recursive option + + path: | : + # The path to a node or event. The path must begin with '/' Usage: diff --git a/docs/client_api/api/free-dep.rst b/docs/client_api/api/free-dep.rst index 5885d40b3..180c4f50b 100644 --- a/docs/client_api/api/free-dep.rst +++ b/docs/client_api/api/free-dep.rst @@ -24,14 +24,21 @@ The following help text is generated by :code:`ecflow_client --help=free-dep` Free dependencies for a node. Defaults to triggers After freeing the time related dependencies (i.e time,today,cron) the next time slot will be missed. - arg1 = (optional) trigger - arg2 = (optional) all - Free trigger, date and all time dependencies - arg3 = (optional) date - Free date dependencies - arg4 = (optional) time - Free all time dependencies i.e time, day, today, cron - arg5 = List of paths. At least one required. Must start with a leading '/' + + Argument(s): + + all: (optional) + # Free trigger, date and all time dependencies + + date: (optional) + # Free date dependencies + + time: (optional) + # Free all time dependencies i.e time, day, today, cron + + paths + # A space separated list of paths. + # At least one path must be provided. Paths must start with a leading '/' Usage: diff --git a/docs/client_api/api/group.rst b/docs/client_api/api/group.rst index 99ff2a7e5..bb018ed80 100644 --- a/docs/client_api/api/group.rst +++ b/docs/client_api/api/group.rst @@ -24,7 +24,12 @@ The following help text is generated by :code:`ecflow_client --help=group` Allows a series of ';' separated commands to be grouped and executed as one. Some commands like halt, shutdown and terminate will prompt the user. To bypass the prompt provide 'yes' as an additional parameter. See example below. - arg = string + + Argument(s): + + arg: string + # A string of ';' separated commands. Each command is the same as if it was + # provided on the command line. The string must be quoted. Usage: diff --git a/docs/client_api/api/halt.rst b/docs/client_api/api/halt.rst index e65acef51..aa61c3095 100644 --- a/docs/client_api/api/halt.rst +++ b/docs/client_api/api/halt.rst @@ -23,7 +23,11 @@ The following help text is generated by :code:`ecflow_client --help=halt` Stop server communication with jobs, and new job scheduling. Also stops automatic check pointing - arg1 = yes(optional) # use to bypass confirmation prompt,i.e. + + Argument(s): + + confirm: (optional) + # value must be "yes"; bypasses the confirmation prompt Usage: diff --git a/docs/client_api/api/init.rst b/docs/client_api/api/init.rst index 710577bc6..c9f2e5cd2 100644 --- a/docs/client_api/api/init.rst +++ b/docs/client_api/api/init.rst @@ -23,9 +23,16 @@ The following help text is generated by :code:`ecflow_client --help=init` Mark task as started(active). For use in the '.ecf' script file *only* Hence the context is supplied via environment variables. - arg1(string) = process_or_remote_id The process id of the job or remote_id - Using remote id allows the jobs to be killed - arg2(--add)(optional)= add/update variables as name value pairs + + Argument(s): + + process_or_remote_id: string + # The process id of the job or remote_id. + # Using remote id allows the jobs to be killed. + + --add: (optional) + # add/update variables as name value pairs + # a list of space separated variables to add/update on this task If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. diff --git a/docs/client_api/api/label.rst b/docs/client_api/api/label.rst index 2de660220..2882df7c6 100644 --- a/docs/client_api/api/label.rst +++ b/docs/client_api/api/label.rst @@ -23,9 +23,14 @@ The following help text is generated by :code:`ecflow_client --help=label` Change Label. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1 = label-name - arg2 = The new label value - The labels values can be single or multi-line(space separated quoted strings) + + Argument(s): + + label-name + # The name of the label to be set. + + value + # The new label value. Can be single or multi-line (space separated quoted strings). If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error diff --git a/docs/client_api/api/load.rst b/docs/client_api/api/load.rst index 813ff3e7a..e6949e7af 100644 --- a/docs/client_api/api/load.rst +++ b/docs/client_api/api/load.rst @@ -28,8 +28,14 @@ The following help text is generated by :code:`ecflow_client --help=load` The suite's can be overwritten if the force option is used. To just check the definition and not send to server, use 'check_only' This command can also be used to load a checkpoint file into the server - arg1 = path to the definition file or checkpoint file - arg2 = (optional) [ force | check_only | print | stats ] # default = false for all + + Argument(s): + + path: + # The path to the definition file or checkpoint file. + + mode: (optional) [ force | check_only | print | stats ] + # The default value is to apply none of the mode options. Usage: diff --git a/docs/client_api/api/log.rst b/docs/client_api/api/log.rst index 28074e0f6..53aa15bea 100644 --- a/docs/client_api/api/log.rst +++ b/docs/client_api/api/log.rst @@ -21,28 +21,37 @@ The following help text is generated by :code:`ecflow_client --help=log` log --- - Get,clear,flush or create a new log file. + Get, clear, flush or create a new log file. The user must ensure that a valid path is specified. Specifying '--log=get' with a large number of lines from the server, can consume a lot of **memory**. The log file can be a very large file, hence we use a default of 100 lines, optionally the number of lines can be specified. - arg1 = [ get | clear | flush | new | path ] - get - Outputs the log file to standard out. - defaults to return the last 100 lines - The second argument can specify how many lines to return - clear - Clear the log file of its contents. - flush - Flush and close the log file. (only temporary) next time - server writes to log, it will be opened again. Hence it best - to halt the server first - new - Flush and close the existing log file, and start using the - the path defined for ECF_LOG. By changing this variable - a new log file path can be used - Alternatively an explicit path can also be provided - in which case ECF_LOG is also updated - path - Returns the path name to the existing log file - arg2 = [ new_path | optional last n lines ] - if get specified can specify lines to get. Value must be convertible to an integer - Otherwise if arg1 is 'new' then the second argument must be a path + + Argument(s): + + action: [ get | clear | flush | new | path ] + # get: Outputs the log file to standard out. + # defaults to return the last 100 lines + # The second argument can specify how many lines to return + # + # clear: Clear the log file of its contents. + # + # flush: Flush and close the log file. (only temporary) next time + # server writes to log, it will be opened again. Hence it best + # to halt the server first + # + # new: Flush and close the existing log file, and start using the + # the path defined for ECF_LOG. By changing this variable + # a new log file path can be used + # Alternatively an explicit path can also be provided + # in which case ECF_LOG is also updated + # + # path: Returns the path name to the existing log file + + value: (optional) [ new_path | optional last n lines ] + # If 'get' is specified, the value specifies lines to get. + # The value must be an integer. + # If 'new' is specified, the value specifies a new path Usage: diff --git a/docs/client_api/api/meter.rst b/docs/client_api/api/meter.rst index 2f3ec10bb..85b6e3092 100644 --- a/docs/client_api/api/meter.rst +++ b/docs/client_api/api/meter.rst @@ -23,8 +23,14 @@ The following help text is generated by :code:`ecflow_client --help=meter` Change meter. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1(string) = meter-name - arg2(int) = the new meter value + + Argument(s): + + meter-name: string + # The name of the meter to be set. + + value: int + # The new meter value If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error diff --git a/docs/client_api/api/msg.rst b/docs/client_api/api/msg.rst index 7d4499a37..df5e0eb3b 100644 --- a/docs/client_api/api/msg.rst +++ b/docs/client_api/api/msg.rst @@ -22,7 +22,11 @@ The following help text is generated by :code:`ecflow_client --help=msg` --- Writes the input string to the log file. - arg1 = string + + Argument(s): + + message: string + # The message to be written to the log file. Usage: diff --git a/docs/client_api/api/order.rst b/docs/client_api/api/order.rst index 15297a35c..ca8beb709 100644 --- a/docs/client_api/api/order.rst +++ b/docs/client_api/api/order.rst @@ -22,8 +22,14 @@ The following help text is generated by :code:`ecflow_client --help=order` ----- Re-orders the nodes held by the server - arg1 = node path - arg2 = [ top | bottom | alpha | order | up | down | runtime] + + Argument(s): + + node: path + # The path to the node to be re-ordered. + + sort-type: [ top | bottom | alpha | order | up | down | runtime] + It should be noted that in the absence of triggers and time/date dependencies, the tasks are submitted in order. This changes the order and hence affects the submission order:: diff --git a/docs/client_api/api/plug.rst b/docs/client_api/api/plug.rst index 19c6097c6..d1b026289 100644 --- a/docs/client_api/api/plug.rst +++ b/docs/client_api/api/plug.rst @@ -24,8 +24,15 @@ The following help text is generated by :code:`ecflow_client --help=plug` Plug command is used to move nodes. The destination node can be on another server In which case the destination path should be of the form ':/suite/family/task - arg1 = path to source node - arg2 = path to the destination node + + Argument(s): + + source: path + # The path to the source node + + destination: path + # The path to the destination node + This command can fail because: - Source node is in a 'active' or 'submitted' state - Another user already has an lock diff --git a/docs/client_api/api/query.rst b/docs/client_api/api/query.rst index 380ecfa27..f625593d3 100644 --- a/docs/client_api/api/query.rst +++ b/docs/client_api/api/query.rst @@ -146,11 +146,17 @@ The following help text is generated by :code:`ecflow_client --help=query` - variable No user or generated variable or repeat of that name found on node or its parents, or (when path is '/') no user or server variable of that name found on the server - trigger Trigger does not parse, or reference to nodes/attributes in the expression are not valid - Arguments: - arg1 = [ state | dstate | repeat | event | meter | label | variable | trigger | limit | limit_max ] - arg2 = | :name where name is name of a event, meter, label, limit or variable. - path '/' represents the server itself, and can only be used with 'state' or 'variable' - arg3 = trigger expression | prev | next # prev,next only used when arg1 is repeat + + Argument(s): + + attribute: [ state | dstate | repeat | event | meter | label | variable | trigger | limit | limit_max ] + # The kind of the attribute to be queried. + + target: | :name + # The path to the node or the node and attribute name. + + value: trigger expression | prev | next + # The values `prev` and `next` are only used when the attribute is a repeat Usage: diff --git a/docs/client_api/api/queue.rst b/docs/client_api/api/queue.rst index 45eeee6ec..4152ea8cb 100644 --- a/docs/client_api/api/queue.rst +++ b/docs/client_api/api/queue.rst @@ -23,15 +23,25 @@ The following help text is generated by :code:`ecflow_client --help=queue` QueueCmd. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1(string) = queue-name: - arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ] - active: returns the first queued/aborted step, the return string is the queue value from the definition - no_of_aborted: returns number of aborted steps as a string, i.e 10 - reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors - arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active) - This is only valid for complete and aborted steps - arg4(string) = path: (optional). The path where the queue is defined. - By default we search for the queue up the node tree. + + Argument(s): + + queue-name: string + # The name of the queue to be used. + + action: string + # [active | aborted | complete | no_of_aborted | reset ] + # active: returns the first queued/aborted step, the return string is the queue value from the definition + # no_of_aborted: returns number of aborted steps as a string, i.e 10 + # reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors + + step: string + # The value returned from `step=$(ecflow_client --queue=queue_name active)` + # This is only valid for complete and aborted steps + + path: (optional) string + # The path where the queue is defined. + # By default we search for the queue up the node tree. If this task command is a zombie, then the default action will be to *block*, The default can be overridden by using zombie attributes. diff --git a/docs/client_api/api/replace.rst b/docs/client_api/api/replace.rst index dc38b4858..1883ed02e 100644 --- a/docs/client_api/api/replace.rst +++ b/docs/client_api/api/replace.rst @@ -23,16 +23,26 @@ The following help text is generated by :code:`ecflow_client --help=replace` Replaces a node in the server, with the given path Can also be used to add nodes in the server - arg1 = path to node - must exist in the client defs(arg2). This is also the node we want to - replace in the server - arg2 = path to client definition file - provides the definition of the new node - arg3 = (optional) [ parent | false ] (default = parent) - create parent families or suite as needed, when arg1 does not - exist in the server - arg4 = (optional) force (default = false) - Force the replacement even if it causes zombies to be created + + Argument(s): + + node: path + # The path to the node to be replaced. + # This path must exist in both the argument `definition` file + # and on the definition currently loaded on the server. + + definition: path + # The path to the client definition file, + # which provides the definition of the new node. + + parent: (optional) [ parent | false ] (default = parent) + # Allows automatically creating parent families or suite as needed, + # when argument `node` does not exist in the server + + force: (optional) (default = false) + # Force the replacement, even if any node is queued/executing. + # Using this option might causes zombies to be created + Replace can fail if: - The node path(arg1) does not exist in the provided client definition(arg2) - The client definition(arg2) must be free of errors diff --git a/docs/client_api/api/requeue.rst b/docs/client_api/api/requeue.rst index dd7ce0633..dcb9da54a 100644 --- a/docs/client_api/api/requeue.rst +++ b/docs/client_api/api/requeue.rst @@ -24,12 +24,17 @@ The following help text is generated by :code:`ecflow_client --help=requeue` Re queues the specified node(s) If any child of the specified node(s) is in a suspended state, this state is cleared Repeats are reset to their starting values, relative time attributes are reset. - arg1 = (optional) [ abort | force ] - abort = re-queue only aborted tasks below node - force = Force the re-queueing even if there are nodes that are active or submitted - = Checks if any tasks are in submitted or active states below the node - if so does nothing. Otherwise re-queues the node. - arg2 = list of node paths. The node paths must begin with a leading '/' character + + Argument(s): + + mode: (optional) [ abort | force ] + # abort = re-queue only aborted tasks below node + # force = Force the re-queueing even if there are nodes that are active or submitted + # = Checks if any tasks are in submitted or active states below the node, + # and if so does nothing. Otherwise, re-queues the node. + + node: path + # A space separared list of node paths. Paths must begin with a leading '/' character Usage: diff --git a/docs/client_api/api/run.rst b/docs/client_api/api/run.rst index 725ef05aa..b3c4b29e2 100644 --- a/docs/client_api/api/run.rst +++ b/docs/client_api/api/run.rst @@ -30,12 +30,18 @@ The following help text is generated by :code:`ecflow_client --help=run` A repeat attribute is incremented when all the child nodes are complete in this case the child nodes are automatically re-queued. Hence this command can be aid, in allowing a Repeat attribute to be incremented - arg1 = (optional)force - Forcibly run, even if there are nodes that are active or submitted - This can result in zombie creation - arg2 = node path(s). The paths must begin with a leading '/' character. - If the path is /suite/family will recursively run all tasks - When providing multiple paths avoid running the same task twice + + Argument(s): + + force: (optional) + # Forcibly run, even if there are nodes that are active or submitted + # This might cause the appearance of zombie + + node: path + # A space separared list of node paths. + # The paths must begin with a leading '/' character. + # If the path points to a suite or a family, all tasks will be run recursively. + # When providing multiple paths avoid running the same task twice Usage: diff --git a/docs/client_api/api/server_load.rst b/docs/client_api/api/server_load.rst index 3c74eee03..7d42a9b93 100644 --- a/docs/client_api/api/server_load.rst +++ b/docs/client_api/api/server_load.rst @@ -34,7 +34,11 @@ The following help text is generated by :code:`ecflow_client --help=server_load` The generated script can be manually changed, to see different rendering effects. i.e. just run 'gnuplot ..gnuplot.script' - arg1 = path to log file + Argument(s): + + log: (optional) path + # The path to the log file. + # If not provided, the log file path is requested from the server. If the path to log file is known, it is *preferable* to use this, rather than requesting the log path from the server. diff --git a/docs/client_api/api/show.rst b/docs/client_api/api/show.rst index 48f3e453a..d12bc7a8d 100644 --- a/docs/client_api/api/show.rst +++ b/docs/client_api/api/show.rst @@ -24,21 +24,27 @@ The following help text is generated by :code:`ecflow_client --help=show` Used to print state of the definition returned from the server to standard output. This command can *only* be used in a group command, and will only work if it is preceded with a get command. See examples below. - arg1 = [ defs | state | migrate ] - The output of show has several options: i.e - o no arguments: With no arguments, print the definition structure to standard output - Extern's are automatically added, allowing the output to be reloaded into the server - i.e --group="get ; show" - o state: - This will output definition structure along with all the state information. - This will include the trigger expressions, abstract syntax tree as comments. - Excludes the edit history - o migrate: - This will output definition structure along with all the state information. - The node state is shown in the comments. - This format allows the definition to be migrated to future version of ecflow. - The output includes edit history but excludes externs. - When the definition is reloaded *NO* checking is done. + + Argument(s): + + output: (optional) [ defs | state | migrate ] + # defs: + # Return the definition structure only, without any state information. + # Necessary `extern`s are automatically added, allowing the output to be + # reloaded into the server e.g., --group="get ; show" + # This is the default if no `output` argument is provided. + # + # state: + # Return definition structure along with all the state information. + # Output includes the trigger expressions' abstract syntax tree (as comment). + # Does not include the edit history + # + # migrate: + # Return definition structure along with all the state information. + # The node state is shown in the comments. + # Use this format to migrate the definition to future version of ecflow. + # The output includes edit history but excludes externs. + # When the definition is reloaded *NO* checking is done. The following shows a summary of the features associated with each choice DEFS STATE MIGRATE diff --git a/docs/client_api/api/shutdown.rst b/docs/client_api/api/shutdown.rst index 6f6b38b19..81479356d 100644 --- a/docs/client_api/api/shutdown.rst +++ b/docs/client_api/api/shutdown.rst @@ -22,7 +22,11 @@ The following help text is generated by :code:`ecflow_client --help=shutdown` -------- Stop server from scheduling new jobs. - arg1 = yes(optional) # use to bypass confirmation prompt,i.e + + Argument(s): + + confirm: (optional) + # value must be "yes"; bypasses the confirmation prompt Usage: diff --git a/docs/client_api/api/terminate.rst b/docs/client_api/api/terminate.rst index 820215e0f..24de64cb3 100644 --- a/docs/client_api/api/terminate.rst +++ b/docs/client_api/api/terminate.rst @@ -22,7 +22,11 @@ The following help text is generated by :code:`ecflow_client --help=terminate` --------- Terminate the server. - arg1 = yes(optional) # use to bypass confirmation prompt.i.e + + Argument(s): + + confirm: (optional) + # value must be "yes"; bypasses the confirmation prompt Usage: diff --git a/docs/client_api/api/wait.rst b/docs/client_api/api/wait.rst index 97f59a76b..0b5cf1c9c 100644 --- a/docs/client_api/api/wait.rst +++ b/docs/client_api/api/wait.rst @@ -23,7 +23,11 @@ The following help text is generated by :code:`ecflow_client --help=wait` Evaluates an expression, and block while the expression is false. For use in the '.ecf' file *only*, hence the context is supplied via environment variables - arg1 = string(expression) + + Argument(s): + + expression: string + # The expression to be evaluated. Usage: diff --git a/docs/client_api/cli_commands.rst b/docs/client_api/cli_commands.rst index b9c5007ec..67aacfa14 100644 --- a/docs/client_api/cli_commands.rst +++ b/docs/client_api/cli_commands.rst @@ -150,7 +150,7 @@ Commands * - :ref:`log_cli` - :term:`user command` - - Get,clear,flush or create a new log file. + - Get, clear, flush or create a new log file. * - :ref:`meter_cli` - :term:`child command` diff --git a/docs/client_api/command_internals.rst b/docs/client_api/command_internals.rst index eaa0df6b4..0c11ee795 100644 --- a/docs/client_api/command_internals.rst +++ b/docs/client_api/command_internals.rst @@ -256,8 +256,11 @@ The zombie handling is the same as for ``InitCmd``. Mark task as aborted. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1 = (optional) string(reason) - Optionally provide a reason why the abort was raised + + Argument(s): + + reason: (optional) string + # Optionally provide a reason why the abort was raised If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. @@ -379,7 +382,11 @@ variables as the job finishes. The zombie handling is the same as for ``InitCmd` Otherwise the blocking period is defined by ECF_TIMEOUT. The init command allows variables to be added, and complete command allows for them to be removed. - arg1(--remove)(optional) = a list of variables to removed from this task + + Argument(s): + + --remove: (optional) + # A list of space separated variables to removed from this task Usage: @@ -519,7 +526,11 @@ synchronisation on the state of other nodes. Evaluates an expression, and block while the expression is false. For use in the '.ecf' file *only*, hence the context is supplied via environment variables - arg1 = string(expression) + + Argument(s): + + expression: string + # The expression to be evaluated. Usage: @@ -652,9 +663,14 @@ complete without error); this can be overridden with zombie attributes. Change event. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1(string | int) = event-name - arg2(string)(optional) = [ set | clear] default value is set + Argument(s): + + event-name: string | int + # The name of the event to be set or cleared. + + state: (optional) string + # [ set | clear], default value is set If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error @@ -806,9 +822,16 @@ zombie attributes, and the blocking period is bounded by ``ECF_TIMEOUT``. Mark task as started(active). For use in the '.ecf' script file *only* Hence the context is supplied via environment variables. - arg1(string) = process_or_remote_id The process id of the job or remote_id - Using remote id allows the jobs to be killed - arg2(--add)(optional)= add/update variables as name value pairs + + Argument(s): + + process_or_remote_id: string + # The process id of the job or remote_id. + # Using remote id allows the jobs to be killed. + + --add: (optional) + # add/update variables as name value pairs + # a list of space separated variables to add/update on this task If this task command is a zombie, then the default action will be to *block*. The default can be overridden by using zombie attributes. @@ -958,9 +981,14 @@ zombie action is to *fob*. Change Label. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1 = label-name - arg2 = The new label value - The labels values can be single or multi-line(space separated quoted strings) + + Argument(s): + + label-name + # The name of the label to be set. + + value + # The new label value. Can be single or multi-line (space separated quoted strings). If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error @@ -1072,8 +1100,14 @@ zombie action is to *fob*. Change meter. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1(string) = meter-name - arg2(int) = the new meter value + + Argument(s): + + meter-name: string + # The name of the meter to be set. + + value: int + # The new meter value If this task command is a zombie, then the default action will be to *fob*, i.e allow the ecflow client command to complete without an error @@ -1197,15 +1231,25 @@ The ``active`` and ``no_of_aborted`` actions return a string; the others return QueueCmd. For use in the '.ecf' script file *only* Hence the context is supplied via environment variables - arg1(string) = queue-name: - arg2(string) = action: [active | aborted | complete | no_of_aborted | reset ] - active: returns the first queued/aborted step, the return string is the queue value from the definition - no_of_aborted: returns number of aborted steps as a string, i.e 10 - reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors - arg3(string) = step: value returned from step=$(ecflow_client --queue=queue_name active) - This is only valid for complete and aborted steps - arg4(string) = path: (optional). The path where the queue is defined. - By default we search for the queue up the node tree. + + Argument(s): + + queue-name: string + # The name of the queue to be used. + + action: string + # [active | aborted | complete | no_of_aborted | reset ] + # active: returns the first queued/aborted step, the return string is the queue value from the definition + # no_of_aborted: returns number of aborted steps as a string, i.e 10 + # reset: sets the index to the first queued/aborted step. Allows steps to be reprocessed for errors + + step: string + # The value returned from `step=$(ecflow_client --queue=queue_name active)` + # This is only valid for complete and aborted steps + + path: (optional) string + # The path where the queue is defined. + # By default we search for the queue up the node tree. If this task command is a zombie, then the default action will be to *block*, The default can be overridden by using zombie attributes. @@ -1863,11 +1907,13 @@ starts. The ``force`` flag is stored in ``force_``; the request below is for ``- Begin playing the definition in the server. Expects zero or a single quoted string. - arg1 = suite-name | Nothing | force - play the chosen suite, if no arg specified, play all suites, in the definition - force means reset the begin status on the suites and bypass checks. - This is only required if suite-name is provide as the first argument - Using force can cause the creation of zombies + + Argument(s): + + suite-name: (optional) + # The name of the selected suite; if not specified, means all suites. + # Including `--force` in the value means reset the begin status and bypass checks. + # Important: using `--force` might cause the appearance of zombies. Usage: @@ -1976,11 +2022,22 @@ the line limit by ``max_lines_``. The reply is always a string. Return the chosen file. Select from [ script | job | jobout | manual | kill | stat ] By default will return the script. - arg1 = path to node - arg2 = (optional) [ script | job | jobout | manual | kill | stat ] - kill will attempt to return output of ECF_KILL_CMD, i.e the file %ECF_JOB%.kill - stat will attempt to return output of ECF_STATUS_CMD, i.e the file %ECF_JOB%.stat - arg3 = (optional) max_lines = 10000 + + Argument(s): + + path: + # The path to the node + + kind: (optional) [ script | job | jobout | manual | kill | stat ] + # `script`: returns the script file, e.g., %ECF_JOB%.ecf + # `job`: returns the pre-processed job script + # `jobout`: returns the job output/log, e.g., %ECF_JOB%.out + # `manual`: returns the job manual + # `kill`: returns the output of ECF_KILL_CMD, e.g., %ECF_JOB%.kill + # `stat`: returns the output of ECF_STATUS_CMD, e.g., %ECF_JOB%.stat + + max_lines: (optional) + # default is 10000 .. tab:: Request @@ -2091,15 +2148,19 @@ save-time alarm. Called with no argument it checkpoints immediately. or by using --alter functionality Note excessive save times can interfere with job scheduling. The alarm threshold can be changed. See below. - arg1 = (optional) mode [ never | on_time | on_time: | always | ] - never : Never check point the definition in the server - on_time : Turn on automatic check pointing at interval stored on server - on_time : Turn on automatic check point, with the specified interval in seconds - alarm : Modify the alarm notification time for check pt saving to disk - always : Check point at any change in node tree, *NOT* recommended for large definitions - : This specifies the interval in seconds when server should automatically check pt. - This will only take effect of mode is on_time/CHECK_ON_TIME - Should ideally be a value greater than 60 seconds, default is 120 seconds + + Argument(s): + + mode: (optional) [ never | on_time | on_time: | always | ] + # never : Never check point the definition in the server + # on_time : Turn on automatic check pointing at interval stored on server + # on_time : Turn on automatic check point, with the specified interval in seconds + # alarm : Modify the alarm notification time for check pt saving to disk + # always : Check point at any change in node tree, *NOT* recommended for large definitions + # : This specifies the interval in seconds when server should automatically check pt. + # + # This only takes effect if mode is on_time/CHECK_ON_TIME + # The default value is 120 seconds, and should be greater than 60 seconds Usage: @@ -2272,8 +2333,15 @@ track a chosen subset of suites and receive only their changes. The operation is Deleted suites will stay registered, and must be explicitly removed/dropped. Note: Suites can be registered before they are loaded into the server This command affects news() and sync() commands - arg1 = true | false # true means add new suites to my list, when they are created - arg2 = names # should be a list of suite names, names not in the definition are ignored + + Argument(s): + + auto-add: true | false + # `true` means add any new suites to user list, when they are created + + names + # A space separated list of suite names. + # Note: names not in the definition are ignored. Usage: @@ -2283,18 +2351,24 @@ track a chosen subset of suites and receive only their changes. The operation is --ch_register=1 true s1 s2 s3 # drop handle 1 then register interest in suites s1,s2,s3 and any new suites # The client handle as the first argument is typically used by GUI/python # When the client handle is no zero, then it is dropped first + To list all suites and handles use --ch_suites
@@ -2328,8 +2415,15 @@ track a chosen subset of suites and receive only their changes. The operation is ------ Remove a set of suites, from an existing handle. - arg1 = handle(integer) # The handle must be an integer that is > 0 - arg2 = names # should be a list of suite names, names not in the definition are ignored + + Argument(s): + + handle: integer + # The handle value (must be an integer > 0) + + names + # A space separated list of suite names. + # Note: names not in the definition are ignored. Usage: @@ -2342,13 +2436,20 @@ track a chosen subset of suites and receive only their changes. The operation is ----------- Change an existing handle so that new suites can be added automatically. - arg1 = handle(integer) # The handle must be an integer that is > 0 - arg2 = true | false # true means add new suites to my list, when they are created + + Argument(s): + + handle: integer + # The handle value (must be an integer > 0) + + auto-add: true | false + # `true` means add new suites to my list, when they are created Usage: --ch_auto_add=10 true # modify handle 10 so that new suites, get added automatically to it --ch_auto_add=10 false # modify handle 10 so that no new suites are added + The handle is created with --ch_register command To list all suites and handles use --ch_suites