Coverage for / home / runner / work / bijux-cli / bijux-cli / src / bijux_cli / cli / commands / config / export.py: 100%
33 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
1# SPDX-License-Identifier: Apache-2.0
2# Copyright © 2025 Bijan Mousavi
4"""Implements the `config export` subcommand for the Bijux CLI.
6This module contains the logic for exporting the application's entire current
7configuration to a specified destination, which can be a file or standard
8output. The output format can be explicitly set to 'env', 'json', or 'yaml',
9or it can be inferred from the destination file's extension.
11Output Contract:
12 * Success (to file): `{"status": "exported", "file": str, "format": str}`
13 * Success (to stdout): The raw exported configuration data is printed directly.
14 * Error: `{"error": str, "code": int}`
16Exit Codes:
17 * `0`: Success.
18 * `1` or `2`: An error occurred during the export process, such as a file
19 write error or invalid format request.
20"""
22from __future__ import annotations
24import platform
26import typer
28from bijux_cli.cli.core.command import (
29 ascii_safe,
30 new_run_command,
31 validate_common_flags,
32)
33from bijux_cli.cli.core.constants import (
34 OPT_FORMAT,
35 OPT_LOG_LEVEL,
36 OPT_PRETTY,
37 OPT_QUIET,
38)
39from bijux_cli.cli.core.help_text import (
40 HELP_FORMAT,
41 HELP_LOG_LEVEL,
42 HELP_NO_PRETTY,
43 HELP_QUIET,
44)
45from bijux_cli.core.di import DIContainer
46from bijux_cli.core.enums import ErrorType
47from bijux_cli.core.errors import ConfigError
48from bijux_cli.core.exit_policy import ExitIntentError
49from bijux_cli.core.precedence import current_execution_policy, resolve_exit_intent
50from bijux_cli.services.config.contracts import ConfigProtocol
53def export_config(
54 ctx: typer.Context,
55 path: str = typer.Argument(
56 ..., help="Destination file – use “-” to write to STDOUT"
57 ),
58 out_fmt: str = typer.Option(
59 None, "--out-format", help="Force output format: env | json | yaml"
60 ),
61 quiet: bool = typer.Option(False, *OPT_QUIET, help=HELP_QUIET),
62 fmt: str = typer.Option("json", *OPT_FORMAT, help=HELP_FORMAT),
63 pretty: bool = typer.Option(True, OPT_PRETTY, help=HELP_NO_PRETTY),
64 log_level: str = typer.Option("info", *OPT_LOG_LEVEL, help=HELP_LOG_LEVEL),
65) -> None:
66 """Exports the current configuration to a file or standard output.
68 This function writes all configuration key-value pairs to a specified
69 destination. If the destination is a file path, a structured JSON/YAML
70 confirmation message is printed to stdout upon success. If the destination
71 is "-", the raw exported configuration is printed directly to stdout.
73 Args:
74 ctx (typer.Context): The Typer context for the CLI.
75 path (str): The destination file path, or "-" for standard output.
76 out_fmt (str): The desired output format ('env', 'json', 'yaml'). If
77 unspecified, it is inferred from the file extension.
78 quiet (bool): If True, suppresses all output except for errors.
79 confirmation payload (file export only).
80 fmt (str): The format for the confirmation payload ("json" or "yaml").
81 pretty (bool): If True, pretty-prints the confirmation payload. log_level (str): Logging level for diagnostics.
83 Returns:
84 None:
86 Raises:
87 SystemExit: Always exits with a contract-compliant status code and
88 payload, indicating success or detailing the error.
89 """
90 command = "config export"
91 effective = current_execution_policy()
92 fmt_lower = validate_common_flags(
93 fmt,
94 command,
95 effective.quiet,
96 include_runtime=effective.include_runtime,
97 log_level=effective.log_level,
98 )
99 quiet = effective.quiet
100 include_runtime = effective.include_runtime
101 pretty = effective.pretty
103 config_svc = DIContainer.current().resolve(ConfigProtocol)
105 try:
106 config_svc.export(path, out_fmt)
107 except ConfigError as exc:
108 code = 2 if getattr(exc, "http_status", 0) == 400 else 1
109 intent = resolve_exit_intent(
110 message=f"Failed to export config: {exc}",
111 code=code,
112 failure="export_failed",
113 command=command,
114 fmt=fmt_lower,
115 quiet=quiet,
116 include_runtime=include_runtime,
117 error_type=ErrorType.INTERNAL,
118 log_level=effective.log_level,
119 )
120 raise ExitIntentError(intent) from exc
122 if path != "-":
124 def payload_builder(include_runtime: bool) -> dict[str, object]:
125 """Builds the payload confirming a successful export to a file.
127 Args:
128 include_runtime (bool): If True, includes Python and platform info.
130 Returns:
131 ConfigExportPayload: The structured payload.
132 """
133 payload: dict[str, object] = {
134 "status": "exported",
135 "file": path,
136 "format": out_fmt or "auto",
137 }
138 if include_runtime:
139 payload.update(
140 {
141 "python": ascii_safe(
142 platform.python_version(), "python_version"
143 ),
144 "platform": ascii_safe(platform.platform(), "platform"),
145 }
146 )
147 return payload
149 new_run_command(
150 command_name=command,
151 payload_builder=payload_builder,
152 quiet=quiet,
153 fmt=fmt_lower,
154 pretty=pretty,
155 log_level=log_level,
156 )