cargo-dry4rust 0.4.0

A cargo subcommand that detects duplicate and near-duplicate code blocks in Rust codebases using AST normalization
Documentation
// Copyright (c) 2026 Matjaz Domen Pecan
// Copyright 2026 Umberto Gotti <umberto.gotti@umbertogotti.dev>
// Licensed under the MIT License
// SPDX-License-Identifier: MIT

use std::path::Path;

use crate::cli::cli_error::CliError;
use crate::cli::cli_error::CliResult;
use crate::cli::command_outcome::CommandOutcome;
use crate::fingerprint::Fingerprint;
use crate::suppression::ignore_file::IgnoreFile;

/// `ignore`: record one fingerprint as a duplicate that is meant to be there.
pub struct IgnoreCommand<'a> {
    root: &'a Path,
    fingerprint: &'a str,
    reason: Option<&'a str>,
}

impl<'a> IgnoreCommand<'a> {
    #[must_use]
    pub const fn new(root: &'a Path, fingerprint: &'a str, reason: Option<&'a str>) -> Self {
        Self {
            root,
            fingerprint,
            reason,
        }
    }

    /// Add the fingerprint to the ignore file.
    ///
    /// # Errors
    ///
    /// Returns [`CliError::InvalidFingerprint`] if the string is not a
    /// fingerprint this tool could have produced, and [`CliError::Io`] if the
    /// ignore file cannot be written.
    pub fn run(&self) -> CliResult<CommandOutcome> {
        let fingerprint = Fingerprint::from_hex(self.fingerprint)
            .ok_or_else(|| CliError::InvalidFingerprint(self.fingerprint.to_owned()))?;
        IgnoreFile::load(self.root)
            .with_ignored(&fingerprint, self.reason.map(ToOwned::to_owned), vec![])
            .save(self.root)?;
        Ok(CommandOutcome::succeeded(format!(
            "Added {} to ignore list.\n",
            self.fingerprint
        )))
    }
}