1use std::{collections::HashMap, path::PathBuf};
3
4use chrono::prelude::*;
5use serde::{Deserialize, Serialize};
6use strum::Display;
7
8#[derive(PartialEq, Eq, Clone, Debug, Display, Serialize, Deserialize)]
11pub enum TaskStatus {
12 Locked { previous_status: Box<TaskStatus> },
14 Stashed { enqueue_at: Option<DateTime<Local>> },
16 Queued { enqueued_at: DateTime<Local> },
18 Running {
20 enqueued_at: DateTime<Local>,
21 start: DateTime<Local>,
22 },
23 Paused {
25 enqueued_at: DateTime<Local>,
26 start: DateTime<Local>,
27 },
28 Done {
30 enqueued_at: DateTime<Local>,
31 start: DateTime<Local>,
32 end: DateTime<Local>,
33 result: TaskResult,
34 },
35}
36
37#[derive(PartialEq, Eq, Clone, Debug, Display, Serialize, Deserialize)]
40pub enum TaskResult {
41 Success,
43 Failed(i32),
45 FailedToSpawn(String),
47 Killed,
49 Errored,
51 DependencyFailed,
53}
54
55#[derive(PartialEq, Eq, Clone, Deserialize, Serialize)]
57pub struct Task {
58 pub id: usize,
59 pub created_at: DateTime<Local>,
60 pub original_command: String,
61 pub command: String,
62 pub path: PathBuf,
63 pub envs: HashMap<String, String>,
64 pub group: String,
65 pub dependencies: Vec<usize>,
66 pub priority: i32,
67 pub label: Option<String>,
68 pub status: TaskStatus,
69}
70
71impl Task {
72 #[allow(clippy::too_many_arguments)]
73 pub fn new(
74 original_command: String,
75 path: PathBuf,
76 envs: HashMap<String, String>,
77 group: String,
78 starting_status: TaskStatus,
79 dependencies: Vec<usize>,
80 priority: i32,
81 label: Option<String>,
82 ) -> Task {
83 Task {
84 id: 0,
85 created_at: Local::now(),
86 original_command: original_command.clone(),
87 command: original_command,
88 path,
89 envs,
90 group,
91 dependencies,
92 priority,
93 label,
94 status: starting_status.clone(),
95 }
96 }
97
98 pub fn start_and_end(&self) -> (Option<DateTime<Local>>, Option<DateTime<Local>>) {
99 match self.status {
100 TaskStatus::Running { start, .. } => (Some(start), None),
101 TaskStatus::Paused { start, .. } => (Some(start), None),
102 TaskStatus::Done { start, end, .. } => (Some(start), Some(end)),
103 _ => (None, None),
104 }
105 }
106
107 pub fn is_running(&self) -> bool {
109 matches!(
110 self.status,
111 TaskStatus::Running { .. } | TaskStatus::Paused { .. }
112 )
113 }
114
115 pub fn is_paused(&self) -> bool {
117 matches!(self.status, TaskStatus::Paused { .. })
118 }
119
120 pub fn is_done(&self) -> bool {
122 matches!(self.status, TaskStatus::Done { .. })
123 }
124
125 pub fn failed(&self) -> bool {
130 match &self.status {
131 TaskStatus::Done { result, .. } => !matches!(result, TaskResult::Success),
132 _ => false,
133 }
134 }
135
136 pub fn is_stashed(&self) -> bool {
138 matches!(self.status, TaskStatus::Stashed { .. })
139 }
140
141 pub fn is_queued(&self) -> bool {
143 matches!(
144 self.status,
145 TaskStatus::Queued { .. }
146 | TaskStatus::Stashed {
147 enqueue_at: Some(_)
148 }
149 )
150 }
151}
152
153impl std::fmt::Debug for Task {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 f.debug_struct("Task")
161 .field("id", &self.id)
162 .field("original_command", &self.original_command)
163 .field("command", &self.command)
164 .field("path", &self.path)
165 .field("envs", &"hidden")
166 .field("group", &self.group)
167 .field("dependencies", &self.dependencies)
168 .field("label", &self.label)
169 .field("status", &self.status)
170 .field("priority", &self.priority)
171 .finish()
172 }
173}