Skip to content

topmark.cli.commands.config_dump

topmark / cli / commands / config_dump

TopMark config dump command.

Emits the effective TopMark configuration as TOML after applying defaults, project/user config files, and any CLI overrides.

The output is wrapped between TOML_BLOCK_START and TOML_BLOCK_END markers for easy parsing in tests or tooling.

Input modes
  • This command is file-agnostic: positional PATHS are rejected.
  • --files-from is accepted for compatibility, but listed paths do not affect the dumped configuration.
  • --include-from - and --exclude-from - are honored for config resolution.
  • '-' as a PATH is rejected; content-on-STDIN is only supported by file-processing commands.

config_dump_command

config_dump_command(
    *,
    verbosity,
    quiet,
    color_mode,
    no_color,
    no_config,
    config_files,
    show_config_layers,
    files_from,
    include_from,
    exclude_from,
    include_patterns,
    exclude_patterns,
    include_file_types,
    exclude_file_types,
    align_fields,
    relative_to,
    output_format,
)

Print the effective merged TopMark configuration.

Builds the effective configuration from defaults, discovered and explicit config files, and CLI overrides, then renders it for human or machine-readable output.

Notes
  • In JSON/NDJSON modes, this command emits a Config snapshot and, when --show-layers is enabled, also emits machine-readable config provenance (still without diagnostics).

Parameters:

Name Type Description Default
verbosity int

Increase TEXT output detail.

required
quiet bool

Suppress TEXT output.

required
color_mode ColorMode | None

Set the color mode (default: auto).

required
no_color bool

bool: If set, disable color mode.

required
no_config bool

If True, skip loading project/user configuration files.

required
config_files list[str]

Additional configuration file paths to load and merge.

required
show_config_layers bool

If True, include a layered TOML provenance view before the final flattened config dump.

required
files_from list[str]

Compatibility input accepted by config dump. Listed paths do not affect the dumped configuration.

required
include_from list[str]

Files that contain include glob patterns (one per line). Use - to read patterns from STDIN.

required
exclude_from list[str]

Files that contain exclude glob patterns (one per line). Use - to read patterns from STDIN.

required
include_patterns list[str]

Glob patterns to include (intersection).

required
exclude_patterns list[str]

Glob patterns to exclude (subtraction).

required
include_file_types list[str]

Restrict processing to the given file type identifiers.

required
exclude_file_types list[str]

Exclude processing for the given file type identifiers.

required
align_fields bool

Whether to align header fields when rendering (captured in config).

required
relative_to str | None

Base path used only for resolving header metadata (e.g., file_relpath).

required
output_format OutputFormat | None

Output format to use (text, markdown, json, or ndjson).

required

Raises:

Type Description
NotImplementedError

When providing an unsupported OutputType.

Source code in src/topmark/cli/commands/config_dump.py
@click.command(
    name=CliCmd.CONFIG_DUMP,
    context_settings=GROUP_CONTEXT_SETTINGS,
    help=(
        "Print the effective merged TopMark configuration as TOML. "
        "This command is file-agnostic: positional PATHS "
        "and file-processing STDIN modes are rejected. "
        f"Use {CliOpt.OUTPUT_FORMAT}={OutputFormat.JSON.value}/{OutputFormat.NDJSON.value} "
        "for machine-readable output."
    ),
    epilog=(
        "\b\n"
        "Examples:\n"
        "  # Print the effective runtime configuration\n"
        f"  topmark {CliCmd.CONFIG} {CliCmd.CONFIG_DUMP}\n"
        "  # Include configuration provenance layers\n"
        f"  topmark {CliCmd.CONFIG} {CliCmd.CONFIG_DUMP} {CliOpt.SHOW_CONFIG_LAYERS}\n"
        "  # Read include patterns from STDIN\n"
        f"  topmark {CliCmd.CONFIG} {CliCmd.CONFIG_DUMP} {CliOpt.INCLUDE_FROM} -\n"
        "  # Emit machine-readable configuration\n"
        f"  topmark {CliCmd.CONFIG} {CliCmd.CONFIG_DUMP} "
        f"{CliOpt.OUTPUT_FORMAT}={OutputFormat.JSON.value}\n"
        "\n"
        "\b\n"
        "Notes:\n"
        "  • File lists are inputs, not configuration; "
        "listed paths do not affect this command's output.\n"
        "  • Pattern sources are configuration and are included in the dump.\n"
        "  • Human output may include TOML block markers when verbosity is enabled.\n"
        "  • Machine-readable formats emit a Config snapshot and optional provenance records.\n"
    ),
)
@common_color_options
@common_text_output_verbosity_options
@common_text_output_quiet_options
@common_config_resolution_options
@config_dump_provenance_options
@config_dump_files_from_options
@common_include_exclude_from_options
@common_file_filtering_options
@common_file_type_filtering_options
@common_header_formatting_options
@common_output_format_options
def config_dump_command(
    *,
    # common_ui_options (verbosity, color):
    verbosity: int,
    quiet: bool,
    color_mode: ColorMode | None,
    no_color: bool,
    # common_config_resolution_options:
    no_config: bool,
    config_files: list[str],
    # config_dump_provenance_options:
    show_config_layers: bool,
    # config_dump_files_from_options:
    files_from: list[str],
    # common_include_exclude_from_options:
    include_from: list[str],
    exclude_from: list[str],
    # common_file_filtering_options:
    include_patterns: list[str],
    exclude_patterns: list[str],
    # common_file_type_filtering_options:
    include_file_types: list[str],
    exclude_file_types: list[str],
    # common_header_formatting_options:
    align_fields: bool,
    relative_to: str | None,
    # common_output_format_options:
    output_format: OutputFormat | None,
) -> None:
    """Print the effective merged TopMark configuration.

    Builds the effective configuration from defaults, discovered and explicit
    config files, and CLI overrides, then renders it for human or machine-readable output.

    Notes:
        - In JSON/NDJSON modes, this command emits a Config snapshot and,
          when `--show-layers` is enabled, also emits machine-readable
          config provenance (still without diagnostics).

    Args:
        verbosity: Increase TEXT output detail.
        quiet: Suppress TEXT output.
        color_mode: Set the color mode (default: auto).
        no_color: bool: If set, disable color mode.
        no_config: If True, skip loading project/user configuration files.
        config_files: Additional configuration file paths to load and merge.
        show_config_layers: If True, include a layered TOML provenance view before
            the final flattened config dump.
        files_from: Compatibility input accepted by config dump. Listed paths do not affect
            the dumped configuration.
        include_from: Files that contain include glob patterns (one per line).
            Use ``-`` to read patterns from STDIN.
        exclude_from: Files that contain exclude glob patterns (one per line).
            Use ``-`` to read patterns from STDIN.
        include_patterns: Glob patterns to *include* (intersection).
        exclude_patterns: Glob patterns to *exclude* (subtraction).
        include_file_types: Restrict processing to the given file type identifiers.
        exclude_file_types: Exclude processing for the given file type identifiers.
        align_fields: Whether to align header fields when rendering (captured in config).
        relative_to: Base path used only for resolving header metadata (e.g., `file_relpath`).
        output_format: Output format to use (``text``, ``markdown``, ``json``, or ``ndjson``).

    Raises:
        NotImplementedError: When providing an unsupported OutputType.
    """
    ctx: click.Context = click.get_current_context()
    state: TopmarkCliState = bootstrap_cli_state(ctx)

    # Effective output format (stored early so shared initialization sees it).
    state.output_format = output_format or OutputFormat.TEXT

    # Initialize the common state (verbosity, color mode) and initialize console
    init_common_state(
        ctx,
        verbosity=verbosity,
        quiet=quiet,
        color_mode=color_mode,
        no_color=no_color,
    )

    # Retrieve effective human facing program-output verbosity for gating extra details
    verbosity_level: int = state.verbosity

    # Machine metadata
    meta: MetaPayload = build_meta_payload()

    # Output format
    fmt: OutputFormat = state.output_format

    apply_color_policy_for_output_format(ctx, fmt=fmt)
    enable_color: bool = state.color_enabled

    # common_from_sources_options - Fail fast if a `--*-from -` option is used without piped STDIN.
    validate_stdin_dash_requires_piped_input(
        ctx,
        files_from=files_from,
        include_from=include_from,
        exclude_from=exclude_from,
    )

    # config_dump_command() is file-agnostic: ignore positional PATHS

    plan: InputPlan = plan_cli_inputs(
        ctx=ctx,
        files_from=files_from or [],
        include_from=include_from,
        exclude_from=exclude_from,
        include_patterns=include_patterns,
        exclude_patterns=exclude_patterns,
        stdin_filename=None,  # We ignore STDIN processing in `config dump`
        allow_empty_paths=True,  # We ignore paths in `config dump`
    )

    prepared_cli_config: PreparedCliConfig = build_resolved_toml_sources_and_config_for_plan(
        ctx=ctx,
        plan=plan,
        no_config=no_config,
        config_paths=config_files,
        strict=None,
        include_file_types=include_file_types,
        exclude_file_types=exclude_file_types,
        align_fields=align_fields,
        relative_to=relative_to,
    )

    run_options: RunOptions = build_run_options(
        apply_changes=False,  # Not relevant for `config dump``
        write_mode=None,  # Not relevant for `config dump``
        stdin_mode=plan.stdin_mode,
        stdin_filename=plan.stdin_filename,
    )

    logger.debug("run options: %s", run_options)

    # Content-to-STDOUT modes: keep stdout clean for the rewritten file content.
    #
    # - STDIN content mode emits the updated file to stdout when --apply is set.
    # - write_mode="stdout" also emits updated content to stdout.
    #
    # In both cases, route all human-facing console output (summaries, warnings,
    # diagnostics) to stderr.
    #
    # Console selection must happen after planning inputs because stdin mode affects routing.
    console: ConsoleProtocol = maybe_route_console_to_stderr(
        ctx,
        run_options=run_options,
        enable_color=enable_color,
    )

    config: FrozenConfig = prepared_cli_config.draft.freeze()
    logger.trace("Run config after layered CLI overrides: %s", config)

    # Render flattened config validation diagnostics before emitting the final dump.
    flattened_diagnostics: FrozenDiagnosticLog = config.validation_logs.flattened()

    if fmt == OutputFormat.TEXT:
        if not state.quiet:
            console.print(
                render_diagnostics_text(
                    diagnostics=flattened_diagnostics,
                    verbosity_level=verbosity_level,
                    color=enable_color,
                )
            )
    elif fmt == OutputFormat.MARKDOWN:
        console.print(
            render_diagnostics_markdown(
                diagnostics=flattened_diagnostics,
            )
        )

    temp_path: Path | None = plan.temp_path  # for cleanup/STDIN-apply branch

    logger.trace(
        "MutableConfig after merging CLI and discovered config: %s",
        prepared_cli_config.draft,
    )

    def _exit() -> None:
        # Cleanup any temp file created by content-on-STDIN mode (defensive)
        if temp_path and temp_path.exists():
            safe_unlink(temp_path)
        ctx.exit(ExitCode.SUCCESS)

    # We don't actually care about the file list here; just dump the config

    if fmt in (OutputFormat.JSON, OutputFormat.NDJSON):
        # Machine-readable formats: emit JSON/NDJSON without human banners
        emit_config_machine(
            console=console,
            meta=meta,
            config=config,
            fmt=fmt,
            resolved_toml=prepared_cli_config.resolved_toml,
            show_config_layers=show_config_layers,
        )
        _exit()

    # Human formats
    report: ConfigDumpHumanReport = build_config_dump_human_report(
        config=config,
        resolved_toml=prepared_cli_config.resolved_toml,
        show_config_layers=show_config_layers,
        verbosity_level=verbosity_level,
        styled=enable_color,
    )

    if fmt == OutputFormat.MARKDOWN:
        console.print(
            render_config_dump_markdown(report),
            nl=False,
        )
        _exit()

    if fmt == OutputFormat.TEXT:
        if not state.quiet:
            console.print(render_config_dump_text(report))
        _exit()

    # Defensive guard in case OutputFormat gains new members
    raise NotImplementedError(f"Unsupported output format: {fmt!r}")