rtask/
error.rs

1//! Error types for Rtask
2
3use std::io;
4use std::path::PathBuf;
5use thiserror::Error;
6
7/// Result type alias for Rtask operations
8pub type Result<T> = std::result::Result<T, RtaskError>;
9
10/// Main error type for Rtask
11#[derive(Error, Debug)]
12pub enum RtaskError {
13    /// Configuration-related errors
14    #[error("Configuration error: {0}")]
15    Config(#[from] ConfigError),
16
17    /// Task execution errors
18    #[error("Execution error: {0}")]
19    Execution(#[from] ExecutionError),
20
21    /// Variable interpolation errors
22    #[error("Interpolation error: {0}")]
23    Interpolation(#[from] InterpolationError),
24
25    /// I/O errors
26    #[error("I/O error: {0}")]
27    Io(#[from] io::Error),
28
29    /// YAML parsing errors
30    #[error("YAML parsing error: {0}")]
31    Yaml(#[from] serde_yaml::Error),
32}
33
34/// Configuration parsing and validation errors
35#[derive(Error, Debug)]
36pub enum ConfigError {
37    #[error("Failed to find config file (searched: {0})")]
38    NotFound(String),
39
40    #[error("Invalid configuration: {0}")]
41    Invalid(String),
42
43    #[error("Task source cannot be defined without target")]
44    SourceWithoutTarget,
45
46    #[error("Task target cannot be defined without source")]
47    TargetWithoutSource,
48
49    #[error("Argument and option '{0}' must have unique names within a task")]
50    DuplicateNames(String),
51
52    #[error("Task '{0}' is not defined")]
53    TaskNotFound(String),
54
55    #[error("Circular dependency detected: {0}")]
56    CircularDependency(String),
57
58    #[error("Failed to include file '{path}': {error}")]
59    IncludeFile { path: PathBuf, error: String },
60}
61
62/// Task execution errors
63#[derive(Error, Debug)]
64pub enum ExecutionError {
65    #[error("Command failed with exit code {0:?}")]
66    CommandFailed(Option<i32>),
67
68    #[error("Failed condition: {0}")]
69    FailedCondition(String),
70
71    #[error("Option '{0}' is required but not provided")]
72    MissingOption(String),
73
74    #[error("Invalid option value for '{name}': {error}")]
75    InvalidOption { name: String, error: String },
76
77    #[error("Cache error: {0}")]
78    Cache(String),
79
80    #[error("Environment error: {0}")]
81    Environment(String),
82}
83
84/// Variable interpolation errors
85#[derive(Error, Debug)]
86pub enum InterpolationError {
87    #[error("Variable '{0}' is not defined")]
88    UndefinedVariable(String),
89
90    #[error("Invalid interpolation syntax: {0}")]
91    InvalidSyntax(String),
92
93    #[error("Recursive interpolation detected")]
94    RecursiveInterpolation,
95}
96
97/// Specialized result type for configuration operations
98pub type ConfigResult<T> = std::result::Result<T, ConfigError>;
99
100/// Specialized result type for execution operations
101pub type ExecutionResult<T> = std::result::Result<T, ExecutionError>;
102
103/// Specialized result type for interpolation operations
104pub type InterpolationResult<T> = std::result::Result<T, InterpolationError>;
105
106/// Helper function to determine if an error represents a failed condition
107/// (which should be treated as a skip, not a hard error)
108pub fn is_failed_condition(err: &ExecutionError) -> bool {
109    matches!(err, ExecutionError::FailedCondition(_))
110}