stackify_common/
types.rs

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    // [a-z0-9]+(?:[._-]{1,2}[a-z0-9]+)*
12    name: String,
13}
14
15impl EnvironmentName {
16    pub fn new(name: &str) -> Result<Self> {
17        // This is the Regex used by Docker for names.
18        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}