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