From 9c98b94358004ccb26996e661b048d4c1a254a13 Mon Sep 17 00:00:00 2001 From: Altynbek Orumbayev Date: Sat, 14 Sep 2024 18:04:36 +0200 Subject: [PATCH] feat: adding flags to enable debug mode; flags for custom path to localnet config --- src/algokit/cli/localnet.py | 49 +++++++++++++++++++++++++++++++++---- src/algokit/core/sandbox.py | 30 +++++++++++++++++++++-- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/algokit/cli/localnet.py b/src/algokit/cli/localnet.py index 501a9858..07ce0267 100644 --- a/src/algokit/cli/localnet.py +++ b/src/algokit/cli/localnet.py @@ -1,4 +1,6 @@ import logging +import os +from pathlib import Path import click import questionary @@ -126,7 +128,26 @@ def config_command(*, engine: str | None, force: bool) -> None: "AlgoKit will not manage the configuration of named LocalNet instances, " "allowing developers to configure it in any way they need.", ) -def start_localnet(name: str | None) -> None: +@click.option( + "--config-dir", + "-P", + "config_path", + type=click.Path(exists=True, readable=True, file_okay=False, resolve_path=True, path_type=Path), + default=lambda: os.environ.get("ALGOKIT_LOCALNET_CONFIG_DIR", None), + required=False, + help="Specify the custom localnet configuration directory.", +) +@click.option( + "--dev/--no-dev", + "-d", + "algod_dev_mode", + is_flag=True, + required=False, + default=True, + type=click.BOOL, + help=("Control whether to launch 'algod' in developer mode or not. Defaults to 'yes'."), +) +def start_localnet(*, name: str | None, config_path: Path | None, algod_dev_mode: bool) -> None: sandbox = ComposeSandbox.from_environment() full_name = f"{SANDBOX_BASE_NAME}_{name}" if name is not None else SANDBOX_BASE_NAME if sandbox is not None and full_name != sandbox.name: @@ -135,7 +156,7 @@ def start_localnet(name: str | None) -> None: sandbox.stop() else: raise click.ClickException("LocalNet is already running. Please stop it first") - sandbox = ComposeSandbox() if name is None else ComposeSandbox(name) + sandbox = ComposeSandbox(SANDBOX_BASE_NAME, config_path) if name is None else ComposeSandbox(name, config_path) compose_file_status = sandbox.compose_file_status() sandbox.check_docker_compose_for_new_image_versions() if compose_file_status is ComposeFileStatus.MISSING: @@ -156,7 +177,16 @@ def start_localnet(name: str | None) -> None: "A named LocalNet is running, update checks are disabled. If you wish to synchronize with the latest " "version, run `algokit localnet reset --update`" ) - sandbox.up() + if sandbox.is_algod_dev_mode() != algod_dev_mode: + sandbox.set_algod_dev_mode(dev_mode=algod_dev_mode) + if click.confirm( + f"Would you like to recreate 'algod' container to apply 'DevMode' flag set to '{algod_dev_mode}'? " + "Otherwise, the next `algokit localnet reset` will restart with the new flag", + default=True, + ): + sandbox.recreate_container("algod") + else: + sandbox.up() @localnet_group.command("stop", short_help="Stop the AlgoKit LocalNet.") @@ -176,10 +206,19 @@ def stop_localnet() -> None: default=False, help="Enable or disable updating to the latest available LocalNet version, default: don't update", ) -def reset_localnet(*, update: bool) -> None: +@click.option( + "--config-dir", + "-P", + "config_path", + type=click.Path(exists=True, readable=True, file_okay=False, resolve_path=True, path_type=Path), + default=lambda: os.environ.get("ALGOKIT_LOCALNET_CONFIG_DIR", None), + required=False, + help="Specify the custom localnet configuration directory.", +) +def reset_localnet(*, update: bool, config_path: Path | None) -> None: sandbox = ComposeSandbox.from_environment() if sandbox is None: - sandbox = ComposeSandbox() + sandbox = ComposeSandbox(config_path=config_path) compose_file_status = sandbox.compose_file_status() if compose_file_status is ComposeFileStatus.MISSING: logger.debug("Existing LocalNet not found; creating from scratch...") diff --git a/src/algokit/core/sandbox.py b/src/algokit/core/sandbox.py index cbaff7d0..ebd4f708 100644 --- a/src/algokit/core/sandbox.py +++ b/src/algokit/core/sandbox.py @@ -46,9 +46,9 @@ def get_min_compose_version() -> str: class ComposeSandbox: - def __init__(self, name: str = SANDBOX_BASE_NAME) -> None: + def __init__(self, name: str = SANDBOX_BASE_NAME, config_path: Path | None = None) -> None: self.name = SANDBOX_BASE_NAME if name == SANDBOX_BASE_NAME else f"{SANDBOX_BASE_NAME}_{name}" - self.directory = get_app_config_dir() / self.name + self.directory = (config_path or get_app_config_dir()) / self.name if not self.directory.exists(): logger.debug(f"The {self.name} directory does not exist yet; creating it") self.directory.mkdir() @@ -128,6 +128,17 @@ def _create_instance_from_data(cls, data: list[dict[str, Any]]) -> ComposeSandbo return cls(name) return None + def set_algod_dev_mode(self, *, dev_mode: bool) -> None: + content = self.algod_network_template_file_path.read_text() + new_value = "true" if dev_mode else "false" + new_content = re.sub(r'"DevMode":\s*(true|false)', f'"DevMode": {new_value}', content) + self.algod_network_template_file_path.write_text(new_content) + + def is_algod_dev_mode(self) -> bool: + content = self.algod_network_template_file_path.read_text() + search = re.search(r'"DevMode":\s*(true|false)', content) + return search is not None and search.group(1) == "true" + def compose_file_status(self) -> ComposeFileStatus: try: compose_content = self.compose_file_path.read_text() @@ -184,6 +195,21 @@ def up(self) -> None: else: logger.warning("AlgoKit LocalNet failed to return a successful health check") + def recreate_container(self, container_name: str) -> None: + logger.info("Recreating the algod container to apply configuration changes...") + self._run_compose_command( + f"stop {container_name}", + bad_return_code_error_message=f"Failed to remove {container_name} container.", + ) + self._run_compose_command( + f"rm -f -v {container_name}", + bad_return_code_error_message=f"Failed to remove {container_name} container.", + ) + self._run_compose_command( + f"up -d {container_name}", + bad_return_code_error_message=f"Failed to recreate {container_name} container.", + ) + def stop(self) -> None: logger.info("Stopping AlgoKit LocalNet now...") self._run_compose_command("stop", bad_return_code_error_message="Failed to stop LocalNet")