Skip to content

Allow specifying global arguments in conf.py #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

- `conf.py` now can contain a `args` dict, which contains arguments available to all products, they can be overridden by product specific or CLI arguments ([#41])

### Fixed

- `--build-arg` was not case-insensitive as claimed in the docs, this has been fixed ([#41])

[#41]: https://github.com/stackabletech/image-tools/pull/41

## [0.0.12] - 2024-07-08

### Added
Expand Down
40 changes: 29 additions & 11 deletions src/image_tools/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def check_architecture_input(architecture: str) -> str:
return architecture


def load_configuration(conf_file_name: str, user_build_args: List[Tuple[str, str]] = []) -> ModuleType:
def load_configuration(conf_file_name: str, cli_build_args: List[Tuple[str, str]] = []) -> ModuleType:
"""Load the configuration module conf.py and potentially override build arguments
with values provided by the user with the --build-arg flag.
The build arguments are key, value pairs from the "conf.products.<product name>.versions.<version>" dictionary.
Expand All @@ -235,18 +235,36 @@ def load_configuration(conf_file_name: str, user_build_args: List[Tuple[str, str
sys.modules[module_name] = module
if spec.loader:
spec.loader.exec_module(module)
override_build_args(module, user_build_args)
assemble_final_build_args(module, cli_build_args)
return module
raise ImportError(name=module_name, path=conf_file_name)

def assemble_final_build_args(conf: ModuleType, cli_build_args: List[Tuple[str, str]] = []) -> None:
cli_build_args = cli_build_args or []
# Convert user_build_args to a dictionary with lowercase keys for easier, case-insensitive lookup
cli_build_args_dict = {k.lower(): v for k, v in cli_build_args}

global_build_args = {k.lower(): v for k, v in (getattr(conf, "args", {}) or {}).items()}

def override_build_args(conf: ModuleType, user_build_args: List[Tuple[str, str]] = []) -> None:
if not user_build_args:
return
# convert user_build_args to a dictionary for easier lookup
user_build_args_dict = {kv[0]: kv[1] for kv in user_build_args}
for product in conf.products:
for conf_build_args in product["versions"]:
for arg in conf_build_args:
if arg in user_build_args_dict:
conf_build_args[arg] = user_build_args_dict[arg]
# Prepare a new list to store the updated dictionaries
updated_args_list = []

# Iterate through each dictionary in the product["args"] list.
# Each of those dictonaries represents a version of a product we build.
for conf_build_args in product.get("versions", []):
# Normalize product-specific arguments to lower case for all handling in here
product_args = {k.lower(): v for k, v in conf_build_args.items()}

# Merge global_build_args and product_args, prioritizing product_args
merged_args = global_build_args.copy()
merged_args.update(product_args)

# Override with CLI-provided args (cli_build_args_dict) -> they have highest priority
final_args = {**merged_args, **cli_build_args_dict}

# Add the final arguments to the updated list
updated_args_list.append(final_args)

# Update product["versions"] with the new list of merged argument dictionaries
product["versions"] = updated_args_list