loq_cli/
lib.rs

1//! Command-line interface for loq.
2//!
3//! Provides the main entry point and CLI argument handling for the loq tool.
4
5#![forbid(unsafe_code)]
6#![warn(missing_docs)]
7
8mod baseline;
9mod baseline_shared;
10mod check;
11mod cli;
12mod config_edit;
13mod init;
14mod output;
15mod relax;
16mod tighten;
17
18use std::ffi::OsString;
19use std::io::{self, Read, Write};
20use std::process::ExitCode;
21
22use clap::Parser;
23use termcolor::{ColorChoice, StandardStream, WriteColor};
24
25use baseline::run_baseline;
26use check::{output_mode, run_check};
27use init::run_init;
28use relax::run_relax;
29use tighten::run_tighten;
30
31pub use cli::{Cli, Command};
32
33/// Exit status for the CLI.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ExitStatus {
36    /// All checks passed.
37    Success,
38    /// Violations found (errors).
39    Failure,
40    /// Runtime error occurred.
41    Error,
42}
43
44impl From<ExitStatus> for ExitCode {
45    fn from(status: ExitStatus) -> Self {
46        match status {
47            ExitStatus::Success => Self::from(0),
48            ExitStatus::Failure => Self::from(1),
49            ExitStatus::Error => Self::from(2),
50        }
51    }
52}
53
54/// Runs the CLI using environment args and stdio.
55#[must_use]
56pub fn run_env() -> ExitStatus {
57    let args = std::env::args_os();
58    let stdin = io::stdin();
59    let mut stdout = StandardStream::stdout(ColorChoice::Auto);
60    let mut stderr = StandardStream::stderr(ColorChoice::Auto);
61    run_with(args, stdin.lock(), &mut stdout, &mut stderr)
62}
63
64/// Runs the CLI with custom args and streams (for testing).
65pub fn run_with<I, R, W1, W2>(args: I, mut stdin: R, stdout: &mut W1, stderr: &mut W2) -> ExitStatus
66where
67    I: IntoIterator<Item = OsString>,
68    R: Read,
69    W1: WriteColor + Write,
70    W2: WriteColor,
71{
72    let cli = Cli::parse_from(args);
73    let mode = output_mode(&cli);
74
75    let default_check = Command::Check(cli::CheckArgs {
76        paths: vec![],
77        no_cache: false,
78        output_format: cli::OutputFormat::Text,
79    });
80    match cli.command.as_ref().unwrap_or(&default_check) {
81        Command::Check(args) => run_check(args, &mut stdin, stdout, stderr, mode),
82        Command::Init(args) => run_init(args, stdout, stderr),
83        Command::Baseline(args) => run_baseline(args, stdout, stderr),
84        Command::Tighten(args) => run_tighten(args, stdout, stderr),
85        Command::Relax(args) => run_relax(args, stdout, stderr),
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn exit_status_to_exit_code() {
95        assert_eq!(ExitCode::from(ExitStatus::Success), ExitCode::from(0));
96        assert_eq!(ExitCode::from(ExitStatus::Failure), ExitCode::from(1));
97        assert_eq!(ExitCode::from(ExitStatus::Error), ExitCode::from(2));
98    }
99}