Skip to main content

dry4rust/cli/
baseline_command.rs

1// Copyright (c) 2026 Matjaz Domen Pecan
2// Copyright 2026 Umberto Gotti <umberto.gotti@umbertogotti.dev>
3// Licensed under the MIT License
4// SPDX-License-Identifier: MIT
5
6use std::fmt::Write as _;
7use std::path::Path;
8
9use crate::analysis::AnalysisResult;
10use crate::cli::cli_error::CliError;
11use crate::cli::cli_error::CliResult;
12use crate::cli::command_outcome::CommandOutcome;
13use crate::config::Config;
14use crate::suppression::baseline_file::BaselineFile;
15use crate::suppression::baseline_file::baseline_path;
16
17/// `baseline`: record the duplication that is already there.
18///
19/// The run behind this command judges nothing -- it cannot, or a second
20/// recording would inherit the first and shrink to nothing. What it writes is
21/// every group found, so a later `check` fails on what is added rather than on
22/// what was found.
23pub struct BaselineCommand<'a> {
24    root: &'a Path,
25    config: &'a Config,
26    result: &'a AnalysisResult,
27    dry_run: bool,
28}
29
30impl<'a> BaselineCommand<'a> {
31    #[must_use]
32    pub const fn new(
33        root: &'a Path,
34        config: &'a Config,
35        result: &'a AnalysisResult,
36        dry_run: bool,
37    ) -> Self {
38        Self {
39            root,
40            config,
41            result,
42            dry_run,
43        }
44    }
45
46    /// Record the current duplication, or say what recording it would hold.
47    ///
48    /// # Errors
49    ///
50    /// Never returns an error itself. A baseline that cannot be written is
51    /// carried in the outcome's result as [`CliError::Analysis`], beside the
52    /// entries already listed, so they still reach stdout ahead of the error.
53    pub fn run(&self) -> CliResult<CommandOutcome> {
54        let path = baseline_path(self.root, self.config.baseline.as_deref());
55        let recorded = BaselineFile::record(self.result);
56
57        let mut out = String::new();
58        for entry in &recorded.entries {
59            let _ = writeln!(
60                out,
61                "  {} {} ({} members: {})",
62                entry.kind,
63                entry.fingerprint,
64                entry.members,
65                entry.names.join(", ")
66            );
67        }
68
69        if self.dry_run {
70            let _ = writeln!(
71                out,
72                "{} groups would be recorded in {}.",
73                recorded.len(),
74                path.display()
75            );
76            return Ok(CommandOutcome::succeeded(out));
77        }
78
79        if let Err(error) = recorded.save(&path) {
80            return Ok(CommandOutcome::new(out, Err(CliError::Analysis(error))));
81        }
82        let _ = writeln!(
83            out,
84            "Recorded {} groups in {}.",
85            recorded.len(),
86            path.display()
87        );
88        Ok(CommandOutcome::succeeded(out))
89    }
90}