diff --git a/docs/reference/qdt_profile.md b/docs/reference/qdt_profile.md index 4d1f4367..b62676f7 100644 --- a/docs/reference/qdt_profile.md +++ b/docs/reference/qdt_profile.md @@ -2,6 +2,8 @@ ## Rules +> Added in version 0.34 + You can add rules to make the profile deployment conditional. In the following example, the profile will be deployed only on Linux: ```json @@ -35,7 +37,7 @@ You can add rules to make the profile deployment conditional. In the following e The rules engine is based on [Python Rule Engine](https://github.com/santalvarez/python-rule-engine/) project whom rules syntax belongs to [JSON Rules Engine](https://github.com/CacheControl/json-rules-engine). -### Conditions +### Conditions and rules context Rules is a set of conditions that use logical operators to compare values with context (a set of facts) which is exposed as a JSON object. Here comes the context for a Linux environment: @@ -44,6 +46,12 @@ Rules is a set of conditions that use logical operators to compare values with c :language: json ``` +To help you writing rules, QDT provides a [command to export rules context](../usage/cli.md#rules-context-export): + +```sh +qdt export-rules-context -o qdt_rules_context.json +``` + ---- ## Model definition diff --git a/docs/usage/cli.md b/docs/usage/cli.md index 3efa3697..cb28d77a 100644 --- a/docs/usage/cli.md +++ b/docs/usage/cli.md @@ -1,7 +1,5 @@ # Command-line interface usage -## Main command - Aliases : `qdt`, `qgis-deployment-toolbelt`, `qdeploy-toolbelt` ```{sphinx_argparse_cli} diff --git a/qgis_deployment_toolbelt/cli.py b/qgis_deployment_toolbelt/cli.py index 09e5751a..c22caae4 100644 --- a/qgis_deployment_toolbelt/cli.py +++ b/qgis_deployment_toolbelt/cli.py @@ -25,7 +25,11 @@ __uri_homepage__, __version__, ) -from qgis_deployment_toolbelt.commands import parser_main_deployment, parser_upgrade +from qgis_deployment_toolbelt.commands.cmd_rules_context import ( + parser_rules_context_export, +) +from qgis_deployment_toolbelt.commands.deployment import parser_main_deployment +from qgis_deployment_toolbelt.commands.upgrade import parser_upgrade from qgis_deployment_toolbelt.utils.journalizer import configure_logger # ############################################################################# @@ -166,6 +170,17 @@ def main(in_args: list[str] = None): add_common_arguments(subcmd_deployment) parser_main_deployment(subcmd_deployment) + # Rules context + subcmd_rules_context = subparsers.add_parser( + "export-rules-context", + help="Export QDT rules context taking into account the local environment to " + "help rules writing.", + formatter_class=main_parser.formatter_class, + prog="rules-context-export", + ) + add_common_arguments(subcmd_rules_context) + parser_rules_context_export(subcmd_rules_context) + # Upgrader subcmd_upgrade = subparsers.add_parser( "upgrade", diff --git a/qgis_deployment_toolbelt/commands/__init__.py b/qgis_deployment_toolbelt/commands/__init__.py index 308ad01e..e69de29b 100644 --- a/qgis_deployment_toolbelt/commands/__init__.py +++ b/qgis_deployment_toolbelt/commands/__init__.py @@ -1,5 +0,0 @@ -#! python3 # noqa: E265 - -# submodules -from .deployment import parser_main_deployment # noqa: F401 -from .upgrade import parser_upgrade # noqa: F401 diff --git a/qgis_deployment_toolbelt/commands/cmd_rules_context.py b/qgis_deployment_toolbelt/commands/cmd_rules_context.py new file mode 100644 index 00000000..68e2c06e --- /dev/null +++ b/qgis_deployment_toolbelt/commands/cmd_rules_context.py @@ -0,0 +1,91 @@ +#! python3 # noqa: E265 + + +""" + Sub-command to export local rules context. + + Author: Julien M. (https://github.com/guts) +""" + + +# ############################################################################ +# ########## IMPORTS ############# +# ################################ + +# standard library +import argparse +import logging +from pathlib import Path + +# package +from qgis_deployment_toolbelt.constants import get_qdt_working_directory +from qgis_deployment_toolbelt.profiles.rules_context import QdtRulesContext +from qgis_deployment_toolbelt.utils.bouncer import exit_cli_error, exit_cli_success + +# ############################################################################ +# ########## GLOBALS ############# +# ################################ + +logger = logging.getLogger(__name__) + + +# ############################################################################ +# ########## CLI ################# +# ################################ + + +def parser_rules_context_export( + subparser: argparse.ArgumentParser, +) -> argparse.ArgumentParser: + """Set the argument parser for subcommand. + + Args: + subparser (argparse.ArgumentParser): parser to set up + + Returns: + argparse.ArgumentParser: parser ready to use + """ + + subparser.add_argument( + "-o", + "--output", + help="Path to the output file where to write rules context.", + default=get_qdt_working_directory().joinpath("export/qdt_rules_context.json"), + type=Path, + dest="output_path", + ) + + subparser.set_defaults(func=run) + + return subparser + + +# ############################################################################ +# ########## MAIN ################ +# ################################ + + +def run(args: argparse.Namespace): + """Run the sub command logic. + + Open result of a previous command. + + Args: + args (argparse.Namespace): arguments passed to the subcommand + """ + logger.debug(f"Running {args.command} with {args}") + + try: + context_json_path = Path(args.output_path) + context_json_path.parent.mkdir(parents=True, exist_ok=True) + rules_context = QdtRulesContext() + + # write into the file passing extra parameters to json.dumps + with context_json_path.open("w", encoding="UTF8") as wf: + wf.write(rules_context.to_json(indent=4, sort_keys=True)) + + # exit nicely + print(f"Rules context exported in {args.output_path}") + exit_cli_success(f"Rules context exported in {args.output_path}") + except Exception as err: + exit_cli_error(err) diff --git a/qgis_deployment_toolbelt/profiles/rules_context.py b/qgis_deployment_toolbelt/profiles/rules_context.py index 2c34bcb4..e34d4ec6 100644 --- a/qgis_deployment_toolbelt/profiles/rules_context.py +++ b/qgis_deployment_toolbelt/profiles/rules_context.py @@ -39,7 +39,6 @@ class QdtRulesContext: - pass @property def _context_date(self) -> dict: diff --git a/tests/test_cli_main.py b/tests/test_cli_main.py index 3391ffe9..945b2151 100644 --- a/tests/test_cli_main.py +++ b/tests/test_cli_main.py @@ -102,7 +102,7 @@ def test_main_run(capsys, option): with pytest.raises(SystemExit): cli.main(option) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == "" # checks @@ -128,7 +128,7 @@ def test_main_run_as_admin(capsys): ] ) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == "" @@ -142,7 +142,7 @@ def test_main_run_unexising_jobs(capsys): ] ) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == "" @@ -151,7 +151,7 @@ def test_main_run_failed(capsys): with pytest.raises(FileExistsError): cli.main(["deploy", f"--scenario={str(sample_scenario_false.resolve())}"]) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == "" @@ -169,12 +169,5 @@ def test_main_run_removing_splash(capsys): ] ) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == "" - - -# ############################################################################# -# ######## Standalone ############## -# ################################## -if __name__ == "__main__": - pass diff --git a/tests/test_cli_rules_context_export.py b/tests/test_cli_rules_context_export.py new file mode 100644 index 00000000..27472771 --- /dev/null +++ b/tests/test_cli_rules_context_export.py @@ -0,0 +1,43 @@ +#! python3 # noqa: E265 + +""" + Test CLI's rules context export command. + + Author: Julien Moura (Oslandia) +""" + +# ############################################################################# +# ########## Libraries ############# +# ################################## + + +# 3rd party +import pytest + +# project +from qgis_deployment_toolbelt import cli + +# ############################################################################# +# ######## Classes ################# +# ################################## + + +@pytest.mark.parametrize("option", ("-h", "--help")) +def test_cli_export_rules_context_help(capsys, option): + """Test CLI help.""" + with pytest.raises(SystemExit): + cli.main(["export-rules-context", option]) + + _, err = capsys.readouterr() + + assert err == "" + + +def test_cli_export_rules_context(capsys): + """Test CLI.""" + with pytest.raises(SystemExit): + cli.main(["export-rules-context"]) + + _, err = capsys.readouterr() + + assert err == "" diff --git a/tests/test_cli_upgrade.py b/tests/test_cli_upgrade.py index 0d12f7e3..85a22298 100644 --- a/tests/test_cli_upgrade.py +++ b/tests/test_cli_upgrade.py @@ -38,7 +38,7 @@ def test_cli_upgrade_check_only(capsys): with pytest.raises(SystemExit): cli.main(["upgrade", "-c"]) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == "" @@ -48,7 +48,7 @@ def test_cli_upgrade_download(capsys): with pytest.raises(SystemExit): cli.main(["upgrade", "-n", "-w", "tests/"]) - out, err = capsys.readouterr() + _, err = capsys.readouterr() assert err == ""