dumpfs 0.1.0

A tool for dumping codebase information for LLMs efficiently and effectively
Documentation
use std::{
    io,
    path::{Path, PathBuf},
};

use tracing::warn;

/// Error types that can occur during the filesystem scan.
#[derive(Debug, thiserror::Error)]
pub enum ScannerError {
    /// Generic I/O error.
    #[error("IO operation failed: {0}")]
    IoOps(#[from] std::io::Error),

    /// I/O error specifically related to accessing a path.
    #[error("IO error accessing path {path}: {source}")]
    Io {
        path: PathBuf,
        #[source]
        source: std::io::Error,
    },

    /// Error originating from the `ignore` crate during walker setup (e.g., bad patterns).
    #[error("Filesystem walk configuration/build error: {0}")]
    WalkBuildError(#[from] ignore::Error),

    /// Error fetching metadata for a filesystem entry.
    #[error("Failed to get metadata for path {path}: {source}")]
    MetadataError {
        path: PathBuf,
        #[source]
        source: std::io::Error,
    },

    /// Error reading the target of a symbolic link.
    #[error("Failed to read symlink target for path {path}: {source}")]
    SymlinkReadError {
        path: PathBuf,
        #[source]
        source: std::io::Error,
    },

    /// Error canonicalizing the root path provided to the scanner.
    #[error("Failed to canonicalize root path {path}: {source}")]
    CanonicalizeError {
        path: PathBuf,
        #[source]
        source: std::io::Error,
    },

    /// The provided root path is invalid (not found, not a directory).
    #[error("Root path not found or is not a directory: {0}")]
    InvalidRoot(PathBuf),

    /// An internal error occurred trying to strip the root prefix from an absolute path.
    #[error("Failed to strip prefix '{prefix}' from path '{path}'")]
    StripPrefixError { prefix: PathBuf, path: PathBuf },

    /// Error during parallel processing, often related to mutex poisoning or Arc unwrapping.
    #[error("Error occurred during parallel processing phase: {0}")]
    ParallelProcessingError(String),

    /// Error specifically during the final construction of the hierarchical node tree.
    #[error("Error during final tree construction: {0}")]
    TreeConstructionError(String),

    /// The scan was cancelled externally via the cancellation handle.
    #[error("Scan was cancelled")]
    Cancelled,

    /// The channel connecting the walker and processors was disconnected.
    #[error("Failed to send path from walker to processor channel (receiver disconnected)")]
    ChannelSendError,

    /// Error building the Rayon thread pool for processors.
    #[error("Failed to build Rayon thread pool: {0}")]
    ThreadPoolBuildError(#[from] rayon::ThreadPoolBuildError),

    // Note: WalkerThreadJoinError is removed; crossbeam::scope handles join errors better.
    /// The walker thread panicked during execution.
    #[error("Walker thread panicked")]
    WalkerThreadPanic,

    /// Custom Formating error
    #[error("Format: {0}")]
    FmtScanError(#[from] crate::fs::FsFmtError),
}

/// Maps an `io::Error` related to metadata fetching to a `ScannerError::MetadataError`.
pub fn map_meta_err(path: &Path, err: io::Error) -> ScannerError {
    warn!(path=%path.display(), error=%err, "Metadata error occurred");
    ScannerError::MetadataError {
        path: path.to_path_buf(),
        source: err,
    }
}

/// Maps an `io::Error` related to symlink reading to a `ScannerError::SymlinkReadError`.
pub fn map_symlink_err(path: &Path, err: io::Error) -> ScannerError {
    warn!(path=%path.display(), error=%err, "Symlink Read Error occurred");
    ScannerError::SymlinkReadError {
        path: path.to_path_buf(),
        source: err,
    }
}