From 25da6f144fa0234f9eb45030e1bcafac0900beb0 Mon Sep 17 00:00:00 2001 From: ByteOtter Date: Sat, 6 Jan 2024 19:10:46 +0100 Subject: [PATCH 1/5] Add rudimentary CLI implementation --- src/cobbler_tftp/cli.py | 109 ++++++++++++++++++++++++++ src/cobbler_tftp/settings/__init__.py | 10 ++- 2 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 src/cobbler_tftp/cli.py diff --git a/src/cobbler_tftp/cli.py b/src/cobbler_tftp/cli.py new file mode 100644 index 0000000..4b3527e --- /dev/null +++ b/src/cobbler_tftp/cli.py @@ -0,0 +1,109 @@ +""" +Cobbler-tftp will be managable as a command-line service. +""" + +import click +import yaml + +from cobbler_tftp.settings import SettingsFactory + +with open( + "src/cobbler_tftp/settings/data/settings.yml", "r", encoding="utf-8" +) as stream: + try: + SETTINGS = yaml.safe_load(stream) + except yaml.YAMLError as exc: + print(exc) + +_context_settings = dict(help_option_names=["-h", "--help"]) + + +@click.group(context_settings=_context_settings, invoke_without_command=True) +@click.pass_context +def cli(ctx): + """ + Cobbler-TFTP - Copyright (c) 2022 The Cobbler Team. (github.com/cobbler)\n + Licensed under the terms of the GPLv2.0 license. + """ + if ctx.invoked_subcommand is None: + click.echo( + "No commands given, try 'cobbler-tftp -h' or 'cobbler-tftp --help' to view usage." + ) + + # Possible default behavior can be invoked here + + +@cli.command() +@click.option( + "--no-daemon", + "-dd", + is_flag=True, + default=not SETTINGS["is_daemon"], # type: ignore + help="Stop cobbler-tftp from running as daemon.", +) +@click.option( + "--enable-automigration", + is_flag=True, + default=SETTINGS["auto_migrate_settings"], # type: ignore + help="Enable auto migration of settings.", +) +@click.option( + "--config", "-c", type=click.Path(), help="Set location of configuration file." +) +@click.option( + "--settings", + "-s", + multiple=True, + help="""Set custom settings in format:\n + ..<...>.=.\n + Your settings must use single quotes. If a single quote appears within a value it must be escaped.""", +) +def start(no_daemon: bool, enable_automigration, config, settings): + """ + Start the cobbler-tftp server. + """ + click.echo(cli.__doc__) + click.echo("Initializing Cobbler-tftp server...") + if no_daemon: + click.echo("'--no-daemon' flag set. Server running in the foreground...") + settings_factory: SettingsFactory = SettingsFactory() + # settings_file = SettingsFactory.load_config_file(settings_factory, config) + # environment_variables = SettingsFactory.load_env_variables(settings_factory) + # cli_arguments = SettingsFactory.load_cli_options( + # settings_factory, daemon, enable_automigration, settings + # ) + application_settings = SettingsFactory.build_settings( + settings_factory, config, settings + ) + else: + click.echo("Cobbler-tftp will be running as a daemon in the background.") + + +@cli.command() +def version(): + """ + Check cobbler-tftp version. If there are any cobbler servers connected their versions will be printed as well. + """ + pass + + +@cli.command() +def print_default_config(): + """ + Print the default application parameters. + """ + pass + + +@cli.command() +def stop(): + """ + Stop the cobbler-tftp server daemon if it is running + """ + pass + + +cli.add_command(start) +cli.add_command(version) +cli.add_command(print_default_config) +cli.add_command(stop) diff --git a/src/cobbler_tftp/settings/__init__.py b/src/cobbler_tftp/settings/__init__.py index 4680399..441065e 100644 --- a/src/cobbler_tftp/settings/__init__.py +++ b/src/cobbler_tftp/settings/__init__.py @@ -2,7 +2,7 @@ import os from pathlib import Path -from typing import Dict, Optional, Union +from typing import Dict, List, Optional, Union import yaml @@ -92,10 +92,14 @@ def __init__(self) -> None: """Initialize a new Settings dicitionary.""" self._settings_dict: SettingsDict = {} - def build_settings(self, config_path: Optional[Path], cli_flags) -> Settings: + def build_settings( + self, config_path: Optional[Path], cli_arguments: List[str] + ) -> Settings: """ Build new Settings object using parameters from all sources. + :param config_path: Path to the configuration file + :param cli_arguments: List of all CLI configuration options :return: Settings object """ @@ -106,7 +110,7 @@ def build_settings(self, config_path: Optional[Path], cli_flags) -> Settings: self.load_env_variables() # Load CLI options - self.load_cli_options(cli_flags) + self.load_cli_options(cli_arguments) if not migrations.validate(self._settings_dict): raise ValueError( From 75297847ef35c0ac51b05bbc5513134c4f19340e Mon Sep 17 00:00:00 2001 From: Affe Null Date: Mon, 8 Jan 2024 11:20:28 +0100 Subject: [PATCH 2/5] Force older setuptools-scm version when on python 3.6 --- setup.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 9b565f0..c29a860 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,7 +21,8 @@ packages = find: include_package_data = True setup_requires = setuptools - setuptools-scm + setuptools-scm>=6.4.2; python_version>"3.6" + setuptools-scm==6.4.2; python_version=="3.6" wheel install_requires = fbtftp>=0.5 From 65992b41869bc7bad35a9a98a5d2b44d033e14ae Mon Sep 17 00:00:00 2001 From: Affe Null Date: Mon, 8 Jan 2024 11:19:11 +0100 Subject: [PATCH 3/5] Implement version command --- changelog.d/13.added | 1 + pyproject.toml | 2 ++ setup.cfg | 3 ++- src/cobbler_tftp/cli.py | 12 +++++++++++- 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 changelog.d/13.added diff --git a/changelog.d/13.added b/changelog.d/13.added new file mode 100644 index 0000000..bed2f36 --- /dev/null +++ b/changelog.d/13.added @@ -0,0 +1 @@ +Enable setuptools-scm diff --git a/pyproject.toml b/pyproject.toml index c45e69f..1d855d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,8 @@ cobbler-tftp = "cobbler_tftp.cli:cli" [tool.isort] profile = "black" +[tool.setuptools_scm] + [tool.towncrier] directory = "changelog.d" filename = "changelog/v{version}.md" diff --git a/setup.cfg b/setup.cfg index c29a860..9843857 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,6 +31,7 @@ install_requires = pyyaml>=6.0 click>=8.0.4; python_version>"3.6" click==8.0.4; python_version=="3.6" + importlib-metadata==3.10.1; python_version=="3.6" importlib-resources==5.4.0; python_version=="3.6" schema>=0.6.7; python_version>"3.6" schema==0.6.7; python_version=="3.6" @@ -60,4 +61,4 @@ dev_requires = [options.packages.find] where=src exclude = - tests* \ No newline at end of file + tests* diff --git a/src/cobbler_tftp/cli.py b/src/cobbler_tftp/cli.py index 4b3527e..3a87b17 100644 --- a/src/cobbler_tftp/cli.py +++ b/src/cobbler_tftp/cli.py @@ -5,8 +5,18 @@ import click import yaml +try: + import importlib.metadata as importlib_metadata +except ImportError: # use backport for Python versions older than 3.8 + import importlib_metadata + from cobbler_tftp.settings import SettingsFactory +try: + __version__ = importlib_metadata.version("cobbler_tftp") +except importlib_metadata.PackageNotFoundError: + __version__ = "unknown (not installed)" + with open( "src/cobbler_tftp/settings/data/settings.yml", "r", encoding="utf-8" ) as stream: @@ -84,7 +94,7 @@ def version(): """ Check cobbler-tftp version. If there are any cobbler servers connected their versions will be printed as well. """ - pass + click.echo(f"Cobbler-tftp {__version__}") @cli.command() From c3b0aed84054cd5acb128fc7be29e46b710c467d Mon Sep 17 00:00:00 2001 From: Affe Null Date: Mon, 8 Jan 2024 11:22:58 +0100 Subject: [PATCH 4/5] Implement print-default-config command --- src/cobbler_tftp/cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cobbler_tftp/cli.py b/src/cobbler_tftp/cli.py index 3a87b17..38e9763 100644 --- a/src/cobbler_tftp/cli.py +++ b/src/cobbler_tftp/cli.py @@ -102,7 +102,8 @@ def print_default_config(): """ Print the default application parameters. """ - pass + settings_factory: SettingsFactory = SettingsFactory() + click.echo(settings_factory.build_settings(None, [])) @cli.command() From f64211787e433718d99a90bcc7d3d602e3819708 Mon Sep 17 00:00:00 2001 From: Affe Null Date: Mon, 8 Jan 2024 13:09:00 +0100 Subject: [PATCH 5/5] Add importlib-resources and importlib-metadata backports as lint dependencies The backports are always required for static type checking even if they are not used. --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.cfg b/setup.cfg index 9843857..9a81295 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,6 +44,8 @@ tests_require = pytest-cov==3.0.0; python_version=="3.6" lint_requires = + importlib-metadata>=3.10.1 + importlib-resources>=5.4.0 pre-commit>=2.0.1 black>=22.1.0 pyright>=0.0.13