Skip to main content

mz_deploy/
cli.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Command-line interface for mz-deploy.
11//!
12//! This module defines the CLI structure and shared types used across commands.
13//!
14//! ## Submodules
15//!
16//! - **[`commands`]** — One module per CLI subcommand (`stage`, `apply`, `compile`, etc.),
17//!   each exposing a `run()` entry point.
18//! - **[`executor`]** — Orchestrates the full command lifecycle: loads configuration,
19//!   establishes database connections, and dispatches to the appropriate command module.
20//! - **`error`** — [`CliError`] enum that unifies all user-facing errors with optional
21//!   hints, re-exported at this level for convenience.
22//!
23//! ## Top-level Items
24//!
25//! - [`display_error`] — Renders a [`CliError`] to stderr with rustc-style colored
26//!   formatting and hint messages.
27
28pub mod commands;
29mod error;
30pub mod executor;
31pub mod extended_help;
32pub mod git;
33pub mod progress;
34mod render;
35
36pub use error::CliError;
37
38/// Display a CLI error and exit with status code 1.
39///
40/// For errors that carry source positions (parse, validation, typecheck),
41/// emits rustc-style output with a caret under the offending token via
42/// [`annotate_snippets`]. Other errors fall back to plain `Display`. The
43/// optional [`CliError::hint`] is appended in either path.
44#[allow(clippy::print_stderr)]
45pub fn display_error(error: &CliError) {
46    use owo_colors::{OwoColorize, Stream, Style};
47
48    let positional = render::to_positional(error);
49    if positional.is_empty() {
50        let error_style = Style::new().bright_red().bold();
51        eprintln!(
52            "{}: {}",
53            "error".if_supports_color(Stream::Stderr, |t| error_style.style(t)),
54            error
55        );
56    } else {
57        for pd in &positional {
58            eprintln!("{}", render::render(pd));
59        }
60    }
61
62    if let Some(hint) = error.hint() {
63        let eq_style = Style::new().bright_blue().bold();
64        eprintln!(
65            "  {} {}",
66            "=".if_supports_color(Stream::Stderr, |t| eq_style.style(t)),
67            format!("help: {}", hint).if_supports_color(Stream::Stderr, |t| t.bold())
68        );
69    }
70
71    std::process::exit(1);
72}