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::io::Write;
7use std::path::Path;
8
9use crate::analysis::AnalysisResult;
10use crate::cli::cli_error::CliError;
11use crate::cli::cli_error::CliResult;
12use crate::config::Config;
13use crate::suppression::baseline_file::BaselineFile;
14use crate::suppression::baseline_file::baseline_path;
15
16/// `baseline`: record the duplication that is already there.
17///
18/// The run behind this command judges nothing -- it cannot, or a second
19/// recording would inherit the first and shrink to nothing. What it writes is
20/// every group found, so a later `check` fails on what is added rather than on
21/// what was found.
22pub struct BaselineCommand<'a> {
23    root: &'a Path,
24    config: &'a Config,
25    result: &'a AnalysisResult,
26    dry_run: bool,
27}
28
29impl<'a> BaselineCommand<'a> {
30    #[must_use]
31    pub const fn new(
32        root: &'a Path,
33        config: &'a Config,
34        result: &'a AnalysisResult,
35        dry_run: bool,
36    ) -> Self {
37        Self {
38            root,
39            config,
40            result,
41            dry_run,
42        }
43    }
44
45    /// Record the current duplication, or say what recording it would hold.
46    ///
47    /// # Errors
48    ///
49    /// Returns [`CliError::Analysis`] if the baseline cannot be written, and
50    /// [`CliError::Io`] if the writer fails.
51    pub fn run(&self, writer: &mut impl Write) -> CliResult {
52        let path = baseline_path(self.root, self.config.baseline.as_deref());
53        let recorded = BaselineFile::record(self.result);
54
55        for entry in &recorded.entries {
56            writeln!(
57                writer,
58                "  {} {} ({} members: {})",
59                entry.kind,
60                entry.fingerprint,
61                entry.members,
62                entry.names.join(", ")
63            )?;
64        }
65
66        if self.dry_run {
67            writeln!(
68                writer,
69                "{} groups would be recorded in {}.",
70                recorded.len(),
71                path.display()
72            )?;
73            return Ok(());
74        }
75
76        recorded.save(&path).map_err(CliError::Analysis)?;
77        writeln!(
78            writer,
79            "Recorded {} groups in {}.",
80            recorded.len(),
81            path.display()
82        )?;
83        Ok(())
84    }
85}