1use std::{
2 fs::canonicalize,
3 path::Path,
4 sync::{mpsc::Receiver, Arc, Mutex},
5};
6
7use anyhow::Error;
8use fluentci_core::deps::{Graph, GraphCommand};
9use fluentci_ext::cache::Cache as CacheExt;
10use fluentci_ext::Extension;
11use fluentci_ext::{archive::tar::czvf::TarCzvf as TarCzvfExt, runner::Runner};
12use fluentci_ext::{archive::zip::Zip as ZipExt, pkgx::Pkgx as PkgxExt};
13use fluentci_secrets::Provider;
14use fluentci_types::{file::File, secret::Secret, service::Service, Output};
15use uuid::Uuid;
16
17pub fn with_exec(
18 graph: Arc<Mutex<Graph>>,
19 args: Vec<String>,
20 ext: Arc<Box<dyn Extension + Send + Sync>>,
21) -> Result<(), Error> {
22 let mut graph = graph.lock().unwrap();
23
24 let id = Uuid::new_v4().to_string();
25 let dep_id = graph.vertices[graph.size() - 1].id.clone();
26 let deps = match graph.size() {
27 1 => vec![],
28 _ => vec![dep_id],
29 };
30 graph.execute(GraphCommand::AddVertex(
31 id.clone(),
32 "exec".into(),
33 args.join(" "),
34 deps,
35 ext,
36 ))?;
37
38 if graph.size() > 2 {
39 let x = graph.size() - 2;
40 let y = graph.size() - 1;
41 graph.execute(GraphCommand::AddEdge(x, y))?;
42 }
43 Ok(())
44}
45
46pub fn with_workdir(
47 graph: Arc<Mutex<Graph>>,
48 path: String,
49 ext: Arc<Box<dyn Extension + Send + Sync>>,
50) -> Result<(), Error> {
51 let mut graph = graph.lock().unwrap();
52
53 if !Path::new(&path).exists() && !path.starts_with("/") {
54 let dir = canonicalize(".").unwrap();
55 let dir = dir.to_str().unwrap();
56 let dir = format!("{}/{}", dir, path);
57 return Err(Error::msg(format!("Path `{}` does not exist", dir)));
58 }
59
60 if !Path::new(&path).exists() {
61 return Err(Error::msg(format!("Path `{}` does not exist", path)));
62 }
63
64 let id = Uuid::new_v4().to_string();
65 let dep_id = graph.vertices[graph.size() - 1].id.clone();
66 let deps = match graph.size() {
67 1 => vec![],
68 _ => vec![dep_id],
69 };
70 graph.execute(GraphCommand::AddVertex(
71 id.clone(),
72 "withWorkdir".into(),
73 path,
74 deps,
75 ext,
76 ))?;
77
78 if graph.size() > 2 {
79 let x = graph.size() - 2;
80 let y = graph.size() - 1;
81 graph.execute(GraphCommand::AddEdge(x, y))?;
82 }
83
84 graph.execute_vertex(&id)?;
85
86 Ok(())
87}
88
89pub fn with_cache(graph: Arc<Mutex<Graph>>, cache_id: String, path: String) -> Result<(), Error> {
90 let mut graph = graph.lock().unwrap();
91 let runner = graph.runner.clone();
92 graph.runner = Arc::new(Box::new(CacheExt::default()));
93 graph.runner.setup()?;
94
95 if let Some(cache) = graph.volumes.iter().find(|v| v.id.clone() == cache_id) {
96 let id = Uuid::new_v4().to_string();
97 let dep_id = graph.vertices[graph.size() - 1].id.clone();
98 let deps = match graph.size() {
99 1 => vec![],
100 _ => vec![dep_id],
101 };
102 let cache_key_path = format!("{}:{}", cache.path, path);
103 graph.execute(GraphCommand::AddVertex(
104 id.clone(),
105 "withCache".into(),
106 cache_key_path,
107 deps,
108 Arc::new(Box::new(CacheExt::default())),
109 ))?;
110
111 let x = graph.size() - 2;
112 let y = graph.size() - 1;
113 graph.execute(GraphCommand::AddEdge(x, y))?;
114
115 graph.execute_vertex(&id)?;
116 graph.runner = runner;
117 return Ok(());
118 }
119
120 return Err(Error::msg("Cache not found"));
121}
122
123pub fn with_file(graph: Arc<Mutex<Graph>>, file_id: String, path: String) -> Result<(), Error> {
124 let mut graph = graph.lock().unwrap();
125 let runner = graph.runner.clone();
126 graph.runner = Arc::new(Box::new(Runner::default()));
127 graph.runner.setup()?;
128
129 if let Some(file) = graph.volumes.iter().find(|v| v.id.clone() == file_id) {
130 let id = Uuid::new_v4().to_string();
131 let dep_id = graph.vertices[graph.size() - 1].id.clone();
132 let deps = match graph.size() {
133 1 => vec![],
134 _ => vec![dep_id],
135 };
136 let copy_file = format!("cp {} {}", file.path, path);
137 graph.execute(GraphCommand::AddVertex(
138 id.clone(),
139 "withFile".into(),
140 copy_file,
141 deps,
142 Arc::new(Box::new(Runner::default())),
143 ))?;
144
145 let x = graph.size() - 2;
146 let y = graph.size() - 1;
147 graph.execute(GraphCommand::AddEdge(x, y))?;
148
149 graph.execute_vertex(&id)?;
150
151 graph.runner = runner;
152 return Ok(());
153 }
154
155 return Err(Error::msg("File not found"));
156}
157
158pub fn stdout(
159 graph: Arc<Mutex<Graph>>,
160 rx: Arc<Mutex<Receiver<(String, usize)>>>,
161) -> Result<String, Error> {
162 let mut graph = graph.lock().unwrap();
163 graph.execute(GraphCommand::Execute(Output::Stdout))?;
164 let rx = rx.lock().unwrap();
165 let (stdout, code) = rx.recv().unwrap();
166
167 if code != 0 {
168 return Err(Error::msg(format!(
169 "Failed to execute command `{}`",
170 stdout
171 )));
172 }
173 Ok(stdout)
174}
175
176pub fn stderr(
177 graph: Arc<Mutex<Graph>>,
178 rx: Arc<Mutex<Receiver<(String, usize)>>>,
179) -> Result<String, Error> {
180 let mut graph = graph.lock().unwrap();
181 graph.execute(GraphCommand::Execute(Output::Stderr))?;
182 let rx = rx.lock().unwrap();
183 let (stderr, code) = rx.recv().unwrap();
184
185 if code != 0 {
186 return Err(Error::msg(format!(
187 "Failed to execute command `{}`",
188 stderr
189 )));
190 }
191
192 Ok(stderr)
193}
194
195pub fn zip(graph: Arc<Mutex<Graph>>, path: String) -> Result<File, Error> {
196 let mut graph = graph.lock().unwrap();
197 graph.runner = Arc::new(Box::new(ZipExt::default()));
198 graph.runner.setup()?;
199
200 let id = Uuid::new_v4().to_string();
201 let dep_id = graph.vertices[graph.size() - 1].id.clone();
202
203 graph.execute(GraphCommand::AddVertex(
204 id.clone(),
205 "zip".into(),
206 path.clone(),
207 vec![dep_id],
208 Arc::new(Box::new(ZipExt::default())),
209 ))?;
210
211 let x = graph.size() - 2;
212 let y = graph.size() - 1;
213 graph.execute(GraphCommand::AddEdge(x, y))?;
214
215 graph.execute_vertex(&id)?;
216
217 let output_file = match path.split('/').last() {
218 Some(file) => format!("{}.zip", file),
219 None => format!("{}.zip", path),
220 };
221
222 let parent_dir = path.split('/').collect::<Vec<&str>>();
223 let parent_dir = parent_dir[..parent_dir.len() - 1].join("/");
224
225 let id = Uuid::new_v4().to_string();
226 let file = File {
227 id: id.clone(),
228 path: format!("{}/{}", parent_dir, output_file),
229 };
230
231 graph.execute(GraphCommand::AddVolume(
232 id,
233 "file".into(),
234 file.path.clone(),
235 ))?;
236
237 Ok(file)
238}
239
240pub fn tar_czvf(graph: Arc<Mutex<Graph>>, path: String) -> Result<File, Error> {
241 let mut graph = graph.lock().unwrap();
242 graph.runner = Arc::new(Box::new(TarCzvfExt::default()));
243 graph.runner.setup()?;
244
245 let id = Uuid::new_v4().to_string();
246 let dep_id = graph.vertices[graph.size() - 1].id.clone();
247
248 graph.execute(GraphCommand::AddVertex(
249 id.clone(),
250 "tar czvf".into(),
251 path.clone(),
252 vec![dep_id],
253 Arc::new(Box::new(TarCzvfExt::default())),
254 ))?;
255
256 let x = graph.size() - 2;
257 let y = graph.size() - 1;
258 graph.execute(GraphCommand::AddEdge(x, y))?;
259
260 graph.execute_vertex(&id)?;
261
262 let output_file = match path.split('/').last() {
263 Some(file) => format!("{}.tar.gz", file),
264 None => format!("{}.tar.gz", path),
265 };
266
267 let parent_dir = path.split('/').collect::<Vec<&str>>();
268 let parent_dir = parent_dir[..parent_dir.len() - 1].join("/");
269
270 let id = Uuid::new_v4().to_string();
271 let file = File {
272 id: id.clone(),
273 path: format!("{}/{}", parent_dir, output_file),
274 };
275
276 graph.execute(GraphCommand::AddVolume(
277 id,
278 "file".into(),
279 file.path.clone(),
280 ))?;
281
282 Ok(file)
283}
284
285pub fn as_service(graph: Arc<Mutex<Graph>>, name: String) -> Result<Service, Error> {
286 let mut graph = graph.lock().unwrap();
287 let runner = graph.runner.clone();
288 graph.runner = Arc::new(Box::new(Runner::default()));
289 graph.runner.setup()?;
290
291 let id = Uuid::new_v4().to_string();
292 let dep_id = graph.vertices[graph.size() - 1].id.clone();
293 let deps = match graph.size() {
294 1 => vec![],
295 _ => vec![dep_id],
296 };
297 graph.execute(GraphCommand::AddVertex(
298 id.clone(),
299 "asService".into(),
300 name,
301 deps,
302 Arc::new(Box::new(Runner::default())),
303 ))?;
304
305 if graph.size() > 2 {
306 let x = graph.size() - 2;
307 let y = graph.size() - 1;
308 graph.execute(GraphCommand::AddEdge(x, y))?;
309
310 graph.register_service(&id);
311 }
312
313 let service = Service { id: id.clone() };
314
315 graph.runner = runner;
316 Ok(service)
317}
318
319pub fn with_service(graph: Arc<Mutex<Graph>>, service_id: String) -> Result<(), Error> {
320 let mut graph = graph.lock().unwrap();
321 match graph.services.iter().find(|s| s.id == service_id) {
322 Some(_) => {
323 graph.execute(GraphCommand::EnableService(service_id.clone()))?;
324 Ok(())
325 }
326 None => Err(Error::msg("Service not found")),
327 }
328}
329
330pub fn with_env_variable(graph: Arc<Mutex<Graph>>, key: &str, value: &str) -> Result<(), Error> {
331 let mut graph = graph.lock().unwrap();
332 graph.execute(GraphCommand::AddEnvVariable(key.into(), value.into()))?;
333 Ok(())
334}
335
336pub fn wait_on(graph: Arc<Mutex<Graph>>, port: u32, timeout: Option<u32>) -> Result<(), Error> {
337 let mut graph = graph.lock().unwrap();
338 let runner = graph.runner.clone();
339 graph.runner = Arc::new(Box::new(PkgxExt::default()));
340 graph.runner.setup()?;
341
342 let id = Uuid::new_v4().to_string();
343 let dep_id = graph.vertices[graph.size() - 1].id.clone();
344 let deps = match graph.size() {
345 1 => vec![],
346 _ => vec![dep_id],
347 };
348 let cmd = format!(
349 "pkgx deno run -A npm:wait-port localhost:{} -t {}",
350 port,
351 timeout.unwrap_or(60) * 1000
352 );
353 graph.execute(GraphCommand::AddVertex(
354 id.clone(),
355 "waitOn".into(),
356 cmd,
357 deps,
358 Arc::new(Box::new(PkgxExt::default())),
359 ))?;
360
361 if graph.size() > 2 {
362 let x = graph.size() - 2;
363 let y = graph.size() - 1;
364 graph.execute(GraphCommand::AddEdge(x, y))?;
365 }
366
367 graph.runner = runner;
368 return Ok(());
369}
370
371pub fn add_secretmanager(graph: Arc<Mutex<Graph>>, provider: Provider) -> Result<String, Error> {
372 let mut graph = graph.lock().unwrap();
373 let id = Uuid::new_v4().to_string();
374 graph.execute(GraphCommand::AddSecretManager(id.clone(), provider))?;
375 Ok(id)
376}
377
378pub fn get_secret(
379 graph: Arc<Mutex<Graph>>,
380 secret_manager_id: &str,
381 name: &str,
382) -> Result<Vec<Secret>, Error> {
383 let mut graph = graph.lock().unwrap();
384 let secret = graph.get_secret(secret_manager_id, name.to_string())?;
385 Ok(secret)
386}
387
388pub fn with_secret_variable(
389 graph: Arc<Mutex<Graph>>,
390 env_name: &str,
391 secret_id: &str,
392 secret_name: &str,
393) -> Result<(), Error> {
394 let mut graph = graph.lock().unwrap();
395 graph.execute(GraphCommand::AddSecretVariable(
396 env_name.into(),
397 secret_id.into(),
398 secret_name.into(),
399 ))?;
400 Ok(())
401}
402
403pub fn set_secret(graph: Arc<Mutex<Graph>>, name: &str, value: &str) -> Result<String, Error> {
404 let mut graph = graph.lock().unwrap();
405 let id = graph.set_secret(name.into(), value.into())?;
406 Ok(id)
407}
408
409pub fn get_secret_plaintext(
410 graph: Arc<Mutex<Graph>>,
411 secret_id: &str,
412 name: &str,
413) -> Result<String, Error> {
414 let graph = graph.lock().unwrap();
415 let secret = graph.get_secret_plaintext(secret_id.into(), name.into())?;
416 Ok(secret)
417}