rskiller 0.2.1

Find and clean Rust project build artifacts and caches with parallel processing
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Represents a Rust project with its associated metadata and build artifacts
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RustProject {
    /// Path to the project directory
    pub path: PathBuf,
    /// Project name (from Cargo.toml)
    pub name: String,
    /// Path to the target directory (if it exists)
    pub target_dir: Option<PathBuf>,
    /// Size of the target directory in bytes
    pub target_size: u64,
    /// Last modification time of the project
    pub last_modified: Option<DateTime<Utc>>,
    /// Whether this is a workspace root
    pub workspace_root: bool,
    /// Whether the project has a Cargo.lock file
    pub has_lock_file: bool,
    /// Number of dependencies in Cargo.toml
    pub dependencies_count: usize,
    /// List of build artifacts found in the project
    pub build_artifacts: Vec<BuildArtifact>,
    /// Size of associated cargo cache
    pub cargo_cache_size: u64,
}

/// Represents a specific build artifact within a project
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BuildArtifact {
    /// Path to the artifact
    pub path: PathBuf,
    /// Type of the artifact
    pub artifact_type: ArtifactType,
    /// Size of the artifact in bytes
    pub size: u64,
    /// Last modification time of the artifact
    pub last_modified: Option<DateTime<Utc>>,
}

/// Types of build artifacts that can be found in Rust projects
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ArtifactType {
    /// Main target directory containing build outputs
    Target,
    /// Incremental compilation cache
    IncrementalCompilation,
    /// Compiled dependencies
    Dependencies,
    /// Compiled examples
    Examples,
    /// Compiled tests
    Tests,
    /// Compiled benchmarks
    Benchmarks,
    /// Cargo registry cache
    CargoRegistry,
    /// Cargo git cache
    CargoGitCache,
    /// Cargo configuration cache
    CargoConfigCache,
}

impl RustProject {
    pub fn total_cleanable_size(&self) -> u64 {
        self.target_size + self.cargo_cache_size
    }

    pub fn format_size(&self, use_gb: bool) -> String {
        let size = self.total_cleanable_size();
        if use_gb {
            format!("{:.2} GB", size as f64 / (1024.0 * 1024.0 * 1024.0))
        } else {
            format!("{:.2} MB", size as f64 / (1024.0 * 1024.0))
        }
    }

    pub fn days_since_modified(&self) -> Option<i64> {
        self.last_modified.map(|dt| {
            let now = Utc::now();
            (now - dt).num_days()
        })
    }

    pub fn is_likely_active(&self) -> bool {
        self.days_since_modified()
            .map(|days| days < 30) // Modified within last 30 days
            .unwrap_or(true) // If we can't determine, assume active for safety
    }
}

impl ArtifactType {
    pub fn description(&self) -> &'static str {
        match self {
            ArtifactType::Target => "Target directory (build outputs)",
            ArtifactType::IncrementalCompilation => "Incremental compilation cache",
            ArtifactType::Dependencies => "Compiled dependencies",
            ArtifactType::Examples => "Compiled examples",
            ArtifactType::Tests => "Compiled tests",
            ArtifactType::Benchmarks => "Compiled benchmarks",
            ArtifactType::CargoRegistry => "Cargo registry cache",
            ArtifactType::CargoGitCache => "Cargo git cache",
            ArtifactType::CargoConfigCache => "Cargo configuration cache",
        }
    }

    pub fn is_safe_to_delete(&self) -> bool {
        match self {
            ArtifactType::Target
            | ArtifactType::IncrementalCompilation
            | ArtifactType::Dependencies
            | ArtifactType::Examples
            | ArtifactType::Tests
            | ArtifactType::Benchmarks => true,
            ArtifactType::CargoRegistry
            | ArtifactType::CargoGitCache
            | ArtifactType::CargoConfigCache => false, // More global, need warning
        }
    }
}