diff --git a/linodecli/configuration/config.py b/linodecli/configuration/config.py index 88c557bd4..d857d0227 100644 --- a/linodecli/configuration/config.py +++ b/linodecli/configuration/config.py @@ -290,7 +290,10 @@ def update( ): print(f"User {username} is not configured.") sys.exit(ExitCodes.USERNAME_ERROR) - if not self.config.has_section(username) or allowed_defaults is None: + if ( + not self.config.has_section(username) + and self.config.default_section is None + ) or allowed_defaults is None: return namespace warn_dict = {} @@ -335,12 +338,6 @@ def write_config(self): to save values they've set, and is used internally to update the config on disk when a new user if configured. """ - - # Create the config path isf necessary - config_path = f"{os.path.expanduser('~')}/.config" - if not os.path.exists(config_path): - os.makedirs(config_path) - with open(_get_config_path(), "w", encoding="utf-8") as f: self.config.write(f) diff --git a/linodecli/configuration/helpers.py b/linodecli/configuration/helpers.py index d80f377ca..b9d502a04 100644 --- a/linodecli/configuration/helpers.py +++ b/linodecli/configuration/helpers.py @@ -15,6 +15,8 @@ "XDG_CONFIG_HOME", f"{os.path.expanduser('~')}/.config" ) +ENV_CONFIG_FILE_PATH = "LINODE_CLI_CONFIG" + # this is a list of browser that _should_ work for web-based auth. This is mostly # intended to exclude lynx and other terminal browsers which could be opened, but # won't work. @@ -38,11 +40,23 @@ def _get_config_path() -> str: :returns: The path to the local config file. :rtype: str """ + custom_path = os.getenv(ENV_CONFIG_FILE_PATH, None) + + if custom_path is not None: + custom_path = os.path.expanduser(custom_path) + if not os.path.exists(custom_path): + os.makedirs(os.path.dirname(custom_path), exist_ok=True) + return custom_path + path = f"{LEGACY_CONFIG_DIR}/{LEGACY_CONFIG_NAME}" if os.path.exists(path): return path - return f"{CONFIG_DIR}/{CONFIG_NAME}" + path = f"{CONFIG_DIR}/{CONFIG_NAME}" + if not os.path.exists(path): + os.makedirs(CONFIG_DIR, exist_ok=True) + + return path def _get_config(load: bool = True): diff --git a/linodecli/help_pages.py b/linodecli/help_pages.py index c249dd8fb..2af635fb3 100644 --- a/linodecli/help_pages.py +++ b/linodecli/help_pages.py @@ -30,6 +30,8 @@ "(e.g. 'v4beta')", "LINODE_CLI_API_SCHEME": "Overrides the target scheme used for API requests. " "(e.g. 'https')", + "LINODE_CLI_CONFIG": "Overrides the default configuration file path. " + "(e.g '~/.linode/my-cli-config')", } HELP_TOPICS = { diff --git a/tests/unit/test_configuration.py b/tests/unit/test_configuration.py index 2c43a078c..4015a69e9 100644 --- a/tests/unit/test_configuration.py +++ b/tests/unit/test_configuration.py @@ -609,3 +609,26 @@ def test_bool_input_default(self, monkeypatch): output = stdout_buf.getvalue() assert "foo [y/N]: " in output assert result + + def test_custom_config_path(self, monkeypatch, tmp_path): + """ + Test use a custom configuration path + """ + conf = self._build_test_config() + custom_path = tmp_path / "test-cli-config" + + with ( + patch.dict( + os.environ, + {"LINODE_CLI_CONFIG": custom_path.absolute().as_posix()}, + ), + ): + conf.write_config() + + configs = custom_path.read_text().splitlines() + expected_configs = self.mock_config_file.splitlines() + + assert len(configs) == len(expected_configs) + 1 + + for i, _ in enumerate(expected_configs): + assert expected_configs[i] == configs[i] diff --git a/wiki/Configuration.md b/wiki/Configuration.md index ed595da48..06006e578 100644 --- a/wiki/Configuration.md +++ b/wiki/Configuration.md @@ -41,6 +41,9 @@ environment variable. If you wish to hide the API Version warning you can use the `LINODE_CLI_SUPPRESS_VERSION_WARNING` environment variable. +You may also specify a custom configuration path using the `LINODE_CLI_CONFIG` environment variable +to replace the default path `~/.config/linode-cli`. + ## Configurable API URL In some cases you may want to run linode-cli against a non-default Linode API URL. diff --git a/wiki/development/Development - Overview.md b/wiki/development/Development - Overview.md index 78cc95d47..a354103f7 100644 --- a/wiki/development/Development - Overview.md +++ b/wiki/development/Development - Overview.md @@ -51,7 +51,8 @@ configure the following: - Overrides for the target API URL (hostname, version, scheme, etc.) This command serves as an interactive prompt and outputs a configuration file to `~/.config/linode-cli`. -This file is in a simple INI format and can be easily modified manually by users. +This file is in a simple INI format and can be easily modified manually by users. +You may also specify a custom configuration file path using the `LINODE_CLI_CONFIG` environment variable. Additionally, multiple users can be created for the CLI which can be designated when running commands using the `--as-user` argument or using the `default-user` config variable.