use thiserror::Error;
#[derive(Error, Debug)]
pub enum FlecheError {
#[error("No fleche.toml found in current directory or parents")]
ConfigNotFound,
#[error("Failed to parse config file: {0}")]
ConfigParse(String),
#[error("Job '{0}' not found. Available jobs: {1}")]
JobNotFound(String, String),
#[error("Duplicate job name '{0}' defined in: {1}")]
DuplicateJob(String, String),
#[error("Missing required field '{0}' in config")]
MissingField(String),
#[error("SSH connection failed: {0}")]
SshConnection(String),
#[error("SSH command failed: {0}")]
SshCommand(String),
#[error("{0}")]
SshTimeout(String),
#[error("Rsync failed: {0}")]
RsyncFailed(String),
#[error("Sbatch submission failed: {0}")]
SbatchFailed(String),
#[error("Job '{0}' not found in registry. Run `fleche status` to see available jobs.")]
JobIdNotFound(String),
#[error("Multiple jobs match '{0}':\n {1}\nUse a longer suffix to disambiguate.")]
AmbiguousJobId(String, String),
#[error("Database error: {0}")]
Database(#[from] rusqlite::Error),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("{context}: {source}")]
IoContext {
context: String,
#[source]
source: std::io::Error,
},
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("Either job-name or --command must be provided")]
NoJobOrCommand,
#[error("Cannot cancel job '{0}': status is {1}")]
CannotCancel(String, String),
#[error("No jobs found. Run 'fleche run' to submit a job.")]
NoRecentJob,
#[error("Invalid duration: {0}. Use format like 7d, 24h, 30m")]
InvalidDuration(String),
#[error("Invalid glob pattern: {0}")]
InvalidGlobPattern(String),
#[error("Invalid regex pattern: {0}")]
InvalidRegexPattern(String),
#[error("Unknown job status: {0}")]
UnknownJobStatus(String),
#[error("Could not query Slurm job status: {0}")]
SlurmQueryFailed(String),
#[error("Could not find config directory")]
ConfigDirNotFound,
#[error("Job '{0}' has no Slurm ID")]
NoSlurmId(String),
#[error("Could not reach Slurm controller")]
SlurmUnavailable,
#[error("{0}")]
MissingDependency(String),
}
pub type Result<T> = std::result::Result<T, FlecheError>;
pub trait IoResultExt<T> {
fn io_context<C, F>(self, context: F) -> Result<T>
where
C: Into<String>,
F: FnOnce() -> C;
}
impl<T> IoResultExt<T> for std::io::Result<T> {
fn io_context<C, F>(self, context: F) -> Result<T>
where
C: Into<String>,
F: FnOnce() -> C,
{
self.map_err(|source| FlecheError::IoContext {
context: context().into(),
source,
})
}
}