1use std::{fmt::Display, ops::Deref, path::PathBuf};
2
3use color_eyre::{eyre::bail, Result};
4use regex::Regex;
5use serde::Serialize;
6
7use crate::{FileType, ServiceType, ValueType};
8
9#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct EnvironmentName {
11 name: String,
13}
14
15impl EnvironmentName {
16 pub fn new(name: &str) -> Result<Self> {
17 let regex = Regex::new("[a-z0-9]+(?:[._-]{1,2}[a-z0-9]+)*")?;
19 if !regex.is_match(name) {
20 bail!(format!("The environment name '{}' is invalid.", name));
21 }
22
23 Ok(Self {
24 name: name.to_string(),
25 })
26 }
27
28 pub fn as_str(&self) -> &str {
29 &self.name
30 }
31}
32
33impl Display for EnvironmentName {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 write!(f, "{}", self.name)
36 }
37}
38
39impl Deref for EnvironmentName {
40 type Target = str;
41
42 fn deref(&self) -> &Self::Target {
43 &self.name
44 }
45}
46
47impl AsRef<str> for EnvironmentName {
48 fn as_ref(&self) -> &str {
49 &self.name
50 }
51}
52
53impl Into<String> for EnvironmentName {
54 fn into(self) -> String {
55 self.name
56 }
57}
58
59impl Into<String> for &EnvironmentName {
60 fn into(self) -> String {
61 self.name.clone()
62 }
63}
64
65impl TryFrom<&str> for EnvironmentName {
66 type Error = color_eyre::eyre::Error;
67
68 fn try_from(name: &str) -> Result<Self> {
69 Self::new(name)
70 }
71}
72
73impl TryFrom<String> for EnvironmentName {
74 type Error = color_eyre::eyre::Error;
75
76 fn try_from(name: String) -> Result<Self> {
77 Self::new(&name)
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct EnvironmentService {
83 pub id: i32,
84 pub service_type: ServiceTypeSimple,
85 pub version: ServiceVersion,
86 pub name: String,
87 pub remark: Option<String>,
88 pub file_headers: Vec<EnvironmentServiceFileHeader>,
89 pub params: Vec<EnvironmentServiceParam>,
90}
91
92impl EnvironmentService {}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct EnvironmentEpoch {
96 pub id: i32,
97 pub epoch: Epoch,
98 pub starts_at_block_height: u32,
99 pub ends_at_block_height: Option<u32>,
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct ServiceTypeSimple {
104 pub id: i32,
105 pub name: String,
106 pub cli_name: String,
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub struct ServiceTypeFull {
111 pub id: i32,
112 pub name: String,
113 pub cli_name: String,
114 pub allow_max_epoch: bool,
115 pub allow_min_epoch: bool,
116 pub allow_git_target: bool,
117 pub versions: Vec<ServiceVersion>,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct ServiceVersion {
122 pub id: i32,
123 pub version: String,
124 pub min_epoch: Option<Epoch>,
125 pub max_epoch: Option<Epoch>,
126 pub git_target: Option<GitTarget>,
127 pub cli_name: String,
128 pub rebuild_required: bool,
129 pub last_built_at: Option<time::PrimitiveDateTime>,
130 pub last_build_commit_hash: Option<String>,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct Epoch {
135 pub id: i32,
136 pub name: String,
137 pub default_block_height: u32,
138}
139
140impl Display for Epoch {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 write!(f, "{} ({})", self.name, self.default_block_height)
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct Environment {
148 pub id: i32,
149 pub name: EnvironmentName,
150 pub services: Vec<EnvironmentService>,
151 pub epochs: Vec<EnvironmentEpoch>,
152 pub keychains: Vec<EnvironmentKeychain>,
153}
154
155impl Environment {
156 pub fn find_service_instances(
157 &self,
158 service_type: ServiceType,
159 name: &str,
160 ) -> Vec<&EnvironmentService> {
161 let service_type_id = service_type as i32;
162
163 self.services
164 .iter()
165 .filter(|service| service.service_type.id == service_type_id)
166 .filter(|svc| &svc.name != name)
167 .collect::<Vec<_>>()
168 }
169}
170
171#[derive(Debug, Clone, PartialEq, Eq)]
172pub enum GitTargetKind {
173 Tag,
174 Branch,
175 Commit,
176}
177
178impl Display for GitTargetKind {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 match self {
181 GitTargetKind::Tag => write!(f, "tag"),
182 GitTargetKind::Branch => write!(f, "branch"),
183 GitTargetKind::Commit => write!(f, "commit"),
184 }
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq)]
189pub struct GitTarget {
190 pub target_type: GitTargetKind,
191 pub target: String,
192}
193
194impl GitTarget {
195 pub fn new(target_type: GitTargetKind, target: &str) -> Self {
196 Self {
197 target_type,
198 target: target.to_string(),
199 }
200 }
201
202 pub fn parse<T: AsRef<str>>(s: T) -> Option<GitTarget> {
203 let s = s.as_ref();
204 let split = s.split(":").collect::<Vec<_>>();
205 if split.len() < 2 {
206 return None;
207 }
208 let target_type = match split[0] {
209 "tag" => GitTargetKind::Tag,
210 "branch" => GitTargetKind::Branch,
211 "commit" => GitTargetKind::Commit,
212 _ => return None,
213 };
214 Some(GitTarget {
215 target_type,
216 target: split[1].to_string(),
217 })
218 }
219
220 pub fn parse_opt<T: AsRef<str>>(s: Option<T>) -> Option<GitTarget> {
221 if let Some(s) = s {
222 Self::parse(s)
223 } else {
224 None
225 }
226 }
227}
228
229#[derive(Debug, Clone)]
230pub struct ServiceTypeFileHeader {
231 pub id: i32,
232 pub service_type: ServiceTypeSimple,
233 pub file_type: FileType,
234 pub filename: String,
235 pub destination_dir: PathBuf,
236 pub description: String,
237}
238
239#[derive(Debug, Clone, PartialEq, Eq)]
240pub struct EnvironmentServiceFileHeader {
241 pub id: i32,
242 pub service_type: ServiceType,
243 pub file_type: FileType,
244 pub filename: String,
245 pub destination_dir: PathBuf,
246 pub description: String,
247}
248
249#[derive(Debug, Clone)]
250pub struct ServiceFileContents {
251 pub contents: Vec<u8>,
252}
253
254pub struct EnvironmentServiceFile {
255 pub header: EnvironmentServiceFileHeader,
256 pub contents: ServiceFileContents,
257}
258
259#[derive(Debug, Clone, PartialEq, Eq)]
260pub struct ServiceTypeParam {
261 pub id: i32,
262 pub service_type: ServiceTypeSimple,
263 pub name: String,
264 pub key: String,
265 pub description: String,
266 pub default_value: String,
267 pub is_required: bool,
268 pub value_type: ValueType,
269 pub allowed_values: Option<Vec<String>>,
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
273pub struct EnvironmentServiceParam {
274 pub id: i32,
275 pub param: ServiceTypeParam,
276 pub value: String,
277}
278
279#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
280pub struct EnvironmentKeychain {
281 pub id: i32,
282 pub environment_id: i32,
283 pub stx_address: String,
284 pub amount: u64,
285 pub mnemonic: String,
286 pub private_key: String,
287 pub public_key: String,
288 pub btc_address: String,
289 pub remark: Option<String>,
290}