From c599c4f9ec9d031f5b51bed175a2489ff0f51c2f Mon Sep 17 00:00:00 2001 From: Filipe Cavalcanti Date: Thu, 5 Feb 2026 09:39:16 -0300 Subject: [PATCH] improvement: improve kconfig CLI and fix write_config issue --- ntxbuild/cli.py | 70 ++++++++++++++++++++++---------------------- ntxbuild/config.py | 23 +++++++++++---- tests/test_cli.py | 8 ++--- tests/test_config.py | 19 ++++++++---- 4 files changed, 69 insertions(+), 51 deletions(-) diff --git a/ntxbuild/cli.py b/ntxbuild/cli.py index 1959140..aa320f7 100644 --- a/ntxbuild/cli.py +++ b/ntxbuild/cli.py @@ -302,59 +302,59 @@ def start(apps_dir, nuttx_dir, store_nxtmpdir, use_cmake, board, defconfig): @main.command() -@click.option("--read", "-r", help="Path to apps folder (relative or absolute)") -@click.option("--set-value", help="Set Kconfig value") -@click.option("--set-str", help="Set Kconfig string") +@click.option("--read", "-r", help="Read Kconfig option", nargs=1) +@click.option("--enable", "-e", help="Enable Kconfig option", nargs=1) +@click.option("--disable", "-d", help="Disable Kconfig option", nargs=1) +@click.option("--set-value", help="Set Kconfig value (int or hex)", nargs=2) +@click.option("--set-str", help="Set Kconfig string", nargs=2) @click.option("--apply", "-a", help="Apply Kconfig options", is_flag=True) -@click.option("--merge", "-m", help="Merge Kconfig file", is_flag=True) -@click.argument("value", nargs=1, required=False) -def kconfig(read, set_value, set_str, apply, value, merge): +@click.option("--merge", "-m", help="Merge Kconfig file", nargs=1) +def kconfig( + read: str, + enable: str, + disable: str, + set_value: str, + set_str: str, + apply: bool, + merge: int, +): """Manage Kconfig options. Provides commands to read, set, and manage Kconfig configuration options. Only one action can be performed at a time. - Args: - read: Path to the Kconfig option to read (use with --read/-r). - set_value: Name of the Kconfig option to set a numerical value - (use with --set-value). Requires value argument. - set_str: Name of the Kconfig option to set a string value - (use with --set-str). Requires value argument. - apply: If True, apply Kconfig changes by running olddefconfig - (use with --apply/-a flag). - merge: If True, merge a Kconfig file (use with --merge/-m flag). - Requires value argument with the source file path. - value: Value to set (for --set-value or --set-str) or source - file path (for --merge). Defaults to None. + Example usage: - Exits with code 0 on success, 1 on error. + ntxbuild kconfig --enable CONFIG_DEBUG_INFO + + ntxbuild kconfig --set-value CONFIG_RAM_START 0x1000 + + ntxbuild kconfig --merge ../configs/my_config """ env = prepare_env() try: config_manager = ConfigManager( env.get("nuttxspace_path"), env.get("nuttx_dir"), env.get("apps_dir") ) - if read: + + if apply: + config_manager.kconfig_apply_changes() + elif merge: + config_manager.kconfig_merge_config_file(merge) + elif read: config_manager.kconfig_read(read) elif set_value: - if not value: - click.echo("❌ Set value is required") - sys.exit(1) - config_manager.kconfig_set_value(set_value, value) + config_manager.kconfig_set_value(set_value[0], set_value[1]) elif set_str: - if not value: - click.echo("❌ Set string is required") - sys.exit(1) - config_manager.kconfig_set_str(set_str, value) - elif apply: - config_manager.kconfig_apply_changes() - elif merge: - if not value: - click.echo("❌ Merge file is required") - sys.exit(1) - config_manager.kconfig_merge_config_file(value) + config_manager.kconfig_set_str(set_str[0], set_str[1]) + elif enable: + config_manager.kconfig_enable(enable) + elif disable: + config_manager.kconfig_disable(disable) else: click.echo("❌ No action specified") + sys.exit(1) + except click.ClickException as e: click.echo(f"❌ {e}") sys.exit(1) diff --git a/ntxbuild/config.py b/ntxbuild/config.py index 962bf11..852bb3b 100644 --- a/ntxbuild/config.py +++ b/ntxbuild/config.py @@ -91,13 +91,14 @@ class KconfigParser(kconfiglib.Kconfig): KCONFIG_FILE = "Kconfig" KCONFIG_CONFIG = ".config" - def __init__(self, nuttx_path: Path, apps_path: Path = None): + def __init__(self, nuttx_path: Path, apps_path: Path = None, warn: bool = False): """Initialize the Kconfig parser. Args: nuttx_path: Path to the NuttX source directory. apps_path: Path to the NuttX apps directory. If None, defaults to nuttx_path.parent / "nuttx-apps". + warn: Whether to show warnings. Defaults to True. Raises: FileNotFoundError: If the apps_path does not exist. @@ -131,7 +132,7 @@ def __init__(self, nuttx_path: Path, apps_path: Path = None): os.chdir(self.nuttx_path) try: - super().__init__(self.KCONFIG_FILE, suppress_traceback=False) + super().__init__(self.KCONFIG_FILE, warn=warn, suppress_traceback=False) except Exception as e: logger.error(f"Error initializing Kconfig parser: {e}") self.environment_context.restore_environment() @@ -159,7 +160,11 @@ class ConfigManager(KconfigParser): """ def __init__( - self, nuttxspace_path: Path, nuttx_dir: str = "nuttx", apps_dir: str = None + self, + nuttxspace_path: Path, + nuttx_dir: str = "nuttx", + apps_dir: str = None, + warnings: bool = False, ): """Initialize the ConfigManager. @@ -170,6 +175,7 @@ def __init__( apps_dir: Name of the NuttX apps directory within the workspace. If None, defaults to "nuttx-apps". Defaults to None. + warnings: Whether to show warnings. Defaults to True. Raises: FileNotFoundError: If the apps directory does not exist. @@ -185,7 +191,7 @@ def __init__( else: self.apps_path = self.nuttxspace_path / "nuttx-apps" - super().__init__(self.nuttx_path, self.apps_path) + super().__init__(self.nuttx_path, self.apps_path, warn=warnings) @kconfig_chdir def kconfig_read(self, config: str) -> str: @@ -218,6 +224,7 @@ def kconfig_read(self, config: str) -> str: ) logger.info(f"Kconfig read: {config}={value}") + print(f"{config}={value}") return value except Exception as e: self.environment_context.restore_environment() @@ -258,7 +265,7 @@ def kconfig_enable(self, config: str) -> int: logger.info(f"Kconfig option '{config}' enabled") else: logger.error(f"Kconfig option '{config}' enable failed") - + self.write_config() return ret except Exception as e: self.environment_context.restore_environment() @@ -299,7 +306,7 @@ def kconfig_disable(self, config: str) -> int: logger.info(f"Kconfig option '{config}' disabled") else: logger.error(f"Kconfig option '{config}' disable failed") - + self.write_config() return ret except Exception as e: self.environment_context.restore_environment() @@ -396,7 +403,9 @@ def kconfig_set_value(self, config: str, value: str) -> int: if not ret: logger.error(f"Kconfig set value: {config}={value} failed") logger.info(f"Kconfig set value: {config}={value}") + self.write_config() return ret + except Exception as e: self.environment_context.restore_environment() raise e @@ -432,6 +441,7 @@ def kconfig_set_str(self, config: str, value: str) -> int: if not ret: logger.error(f"Kconfig set string: {config}={value} failed") logger.info(f"Kconfig set string: {config}={value}") + self.write_config() return ret except Exception as e: self.environment_context.restore_environment() @@ -487,6 +497,7 @@ def kconfig_merge_config_file(self, source_file: str) -> int: logger.info(f"Kconfig merge config file: {source_file}") source_file = Path(source_file).resolve().as_posix() result = self.load_config(str(source_file), replace=False) + self.write_config() logger.info(f"Kconfig merge config file result: {result}") except Exception as e: self.environment_context.restore_environment() diff --git a/tests/test_cli.py b/tests/test_cli.py index f2231bd..9697831 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -393,7 +393,7 @@ def test_kconfig_set_value_missing_value(self, nuttxspace_path): result = runner.invoke(kconfig, ["--set-value", "CONFIG_SYSTEM_NSH_PRIORITY"]) assert result.exit_code != 0 - assert "Set value is required" in result.output + assert "Option '--set-value' requires 2 arguments." in result.output def test_kconfig_set_str(self, nuttxspace_path): """Test kconfig set-str command.""" @@ -410,7 +410,7 @@ def test_kconfig_set_str_missing_value(self, nuttxspace_path): result = runner.invoke(kconfig, ["--set-str", "CONFIG_NSH_PROMPT_STRING"]) assert result.exit_code != 0 - assert "Set string is required" in result.output + assert "Option '--set-str' requires 2 arguments." in result.output def test_kconfig_apply(self, nuttxspace_path): """Test kconfig apply command.""" @@ -442,14 +442,14 @@ def test_kconfig_merge_missing_file(self, nuttxspace_path): result = runner.invoke(kconfig, ["--merge"]) assert result.exit_code != 0 - assert "Merge file is required" in result.output + assert "Option '--merge' requires an argument." in result.output def test_kconfig_no_action(self, nuttxspace_path): """Test kconfig command without any action specified.""" runner = CliRunner() result = runner.invoke(kconfig, []) - assert result.exit_code == 0 + assert result.exit_code == 1 assert "No action specified" in result.output def test_kconfig_without_ntxenv(self, nuttxspace_path): diff --git a/tests/test_config.py b/tests/test_config.py index 6b5034d..fbb59ba 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -91,16 +91,23 @@ def test_merge_config(nuttxspace_path): this_file = Path(__file__).resolve() config_file = this_file.parent / "configs" / "test_config" + + value_before_nsh = config_manager.kconfig_read("CONFIG_NSH_SYSINITSCRIPT") + value_before_dd = config_manager.kconfig_read("CONFIG_SYSTEM_DD") + value_before_gpio = config_manager.kconfig_read("CONFIG_DEV_GPIO_NSIGNALS") + assert config_file.exists() config_manager.kconfig_merge_config_file(config_file) config_manager.kconfig_apply_changes() - value = config_manager.kconfig_read("CONFIG_NSH_SYSINITSCRIPT") - assert value == "test_value" - value = config_manager.kconfig_read("CONFIG_SYSTEM_DD") - assert value == "n" - value = config_manager.kconfig_read("CONFIG_DEV_GPIO_NSIGNALS") - assert value == "2" + new_config_manager = ConfigManager(nuttxspace_path, "nuttx") + + value = new_config_manager.kconfig_read("CONFIG_NSH_SYSINITSCRIPT") + assert value == "test_value" and value != value_before_nsh + value = new_config_manager.kconfig_read("CONFIG_SYSTEM_DD") + assert value == "n" and value != value_before_dd + value = new_config_manager.kconfig_read("CONFIG_DEV_GPIO_NSIGNALS") + assert value == "2" and value != value_before_gpio # Exception tests