thot_core/project/
script.rs1use crate::result::{Error, Result, ScriptError};
2use crate::types::{ResourceId, ResourcePath};
3use chrono::prelude::*;
4use std::collections::HashMap;
5use std::ffi::OsStr;
6use std::path::Path;
7
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[derive(Debug, Clone)]
18pub struct Script {
19 pub rid: ResourceId,
20 pub path: ResourcePath,
21 pub name: Option<String>,
22 pub description: Option<String>,
23 pub env: ScriptEnv,
24 pub creator: Option<ResourceId>,
25 created: DateTime<Utc>,
26}
27
28impl Script {
29 pub fn new(path: ResourcePath) -> Result<Self> {
30 let file_name = path.as_path().file_name();
32 if file_name.is_none() {
33 return Err(Error::ScriptError(ScriptError::UnknownLanguage(None)));
34 }
35
36 let file_name = Path::new(file_name.unwrap());
37 let env = ScriptEnv::new(file_name)?;
38
39 Ok(Script {
41 rid: ResourceId::new(),
42 path,
43 name: None,
44 description: None,
45 creator: None,
46 created: Utc::now(),
47 env,
48 })
49 }
50
51 pub fn created(&self) -> &DateTime<Utc> {
55 &self.created
56 }
57}
58
59#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[derive(Debug, Default)]
66pub struct Scripts {
67 pub scripts: Vec<Script>,
68}
69
70impl Scripts {
71 pub fn new() -> Self {
72 Scripts {
73 scripts: Vec::new(),
74 }
75 }
76
77 pub fn get(&self, rid: &ResourceId) -> Option<&Script> {
80 for script in &self.scripts {
81 if &script.rid == rid {
82 return Some(script);
83 }
84 }
85
86 None
87 }
88
89 pub fn contains(&self, rid: &ResourceId) -> bool {
91 self.get(rid).is_some()
92 }
93
94 pub fn contains_path(&self, path: &ResourcePath) -> bool {
96 self.by_path(path).is_some()
97 }
98
99 pub fn by_path(&self, path: &ResourcePath) -> Option<&Script> {
101 for script in &self.scripts {
102 if &script.path == path {
103 return Some(&script);
104 }
105 }
106
107 None
108 }
109}
110
111#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117#[derive(Debug, Clone)]
118pub struct ScriptEnv {
119 pub language: ScriptLang,
120 pub cmd: String,
121 pub args: Vec<String>,
122 pub env: HashMap<String, String>,
123}
124
125impl ScriptEnv {
126 pub fn new(script: &Path) -> Result<Self> {
128 let path_ext = script.extension();
129 if path_ext.is_none() {
130 return Err(Error::ScriptError(ScriptError::UnknownLanguage(None)));
131 }
132
133 let path_ext = path_ext.unwrap();
135 let language = ScriptLang::from_extension(path_ext);
136 if language.is_none() {
137 return Err(Error::ScriptError(ScriptError::UnknownLanguage(Some(
138 path_ext.to_os_string(),
139 ))));
140 }
141 let language = language.unwrap();
142
143 let cmd = match &language {
145 ScriptLang::Python => "python",
146 ScriptLang::R => "Rscript",
147 };
148 let cmd = cmd.to_string();
149
150 let args = Vec::new();
152
153 let env = HashMap::new();
155
156 Ok(ScriptEnv {
157 language,
158 cmd,
159 args,
160 env,
161 })
162 }
163}
164
165#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
171#[derive(Debug, Clone)]
172pub enum ScriptLang {
173 Python,
174 R,
175}
176
177impl ScriptLang {
178 pub fn from_extension(ext: &OsStr) -> Option<Self> {
181 let ext = ext.to_str();
182 if ext.is_none() {
183 return None;
184 }
185
186 match ext.unwrap() {
187 "py" => Some(Self::Python),
188 "r" => Some(Self::R),
189 _ => None,
190 }
191 }
192}
193
194#[cfg(test)]
195#[path = "./script_test.rs"]
196mod script_test;