1use crate::{
6 Sheet, aim::{ Rule, Workflow, WorkflowLike}, expressions::Reference, reference::parse_identifier, values::{Instance, Node}
7};
8use anyhow::{Result, anyhow};
9use once_cell::sync::{
10 Lazy,
11 OnceCell,
12};
13use std::{
14 fs,
15 path::{Path, PathBuf},
16 sync::{Arc, RwLock},
17};
18
19static WORKSPACE_PATH: OnceCell<PathBuf> = OnceCell::new();
20pub struct BasePath {}
21impl BasePath {
22 pub fn init(path: &Path) -> Result<()> {
23 let basepath = path.parent().unwrap_or(Path::new("")).to_path_buf();
24 fs::create_dir_all(&basepath)?;
25 WORKSPACE_PATH.set(basepath)
26 .map_err(|_| anyhow!("Workspace path already initialized"))
27 }
28
29 pub fn convert(locator: &Reference) -> Result<Arc<PathBuf>> {
30 let base_path = WORKSPACE_PATH.get()
31 .ok_or_else(|| anyhow!("Workspace path not initialized"))?;
32
33 if let Reference::One(one) = locator {
34 if one.as_ref() == "_" {
35 return Ok(Arc::new(base_path.join("workspace.aim")));
36 }
37 }
38 let root_path = base_path.join("workspace");
39 std::fs::create_dir_all(&root_path)?;
40
41 Ok(Arc::new(match locator {
42 Reference::One(one) => {
43 if !root_path.exists() {
44 fs::create_dir_all(&root_path)?;
45 }
46 root_path.join(format!("{}.aim", one))
47 }
48 Reference::Two(one, two) => {
49 let branch_path = root_path.join(one.as_ref());
50 if !branch_path.exists() {
51 fs::create_dir_all(&branch_path)?;
52 }
53 branch_path.join(format!("{}.aim", two))
54 }
55 Reference::Three(one, two, three) => {
56 let branch_path = root_path.join(one.as_ref()).join(two.as_ref());
57 if !branch_path.exists() {
58 fs::create_dir_all(&branch_path)?;
59 }
60 branch_path.join(format!("{}.aim", three))
61 }
62 Reference::Four(one, two, three, four) => {
63 let branch_path = root_path.join(one.as_ref()).join(two.as_ref()).join(three.as_ref());
64 if !branch_path.exists() {
65 fs::create_dir_all(&branch_path)?;
66 }
67 branch_path.join(format!("{}.aim", four))
68 }
69 }))
70 }
71}
72
73pub struct Workspace {
77 node: Node,
78}
79
80static GLOBAL_WORKSPACE: Lazy<RwLock<Workspace>> =
82 Lazy::new(|| RwLock::new(Workspace::new()));
83
84fn get_workspace_lock() -> &'static RwLock<Workspace> {
86 &GLOBAL_WORKSPACE
87}
88
89impl Workspace {
90 fn new() -> Self {
92 Workspace {
93 node: Node::init_default(Reference::workspace()),
95 }
96 }
97
98 pub fn workflow() -> Result<Arc<Workflow>> {
99 let read_guard = get_workspace_lock().read()
100 .expect("Lock poisoned in workflow() workspace read.");
101 read_guard.node.get_workflow()
102 }
103
104 pub fn create(path: Arc<PathBuf>) -> Result<Sheet> {
109 match BasePath::init(&path) {
110 Ok(_) => {
111 let mut workspace = Workflow::new_from(Reference::workspace(), path);
113 workspace.add_node(Arc::from("context"), Node::default())?;
114 workspace.add_node(Arc::from("inference"), Node::default())?;
115 workspace.add_node(Arc::from("status"), Node::default())?;
116 workspace.add_node(Arc::from("tool"), Node::default())?;
117 workspace.add_node(Arc::from("workflow"), Node::default())?;
118 workspace.save()?;
119 let write_guard = get_workspace_lock().write()
121 .expect("Lock poisoned in create() workspace write.");
122 write_guard.node.set_workflow(workspace);
123 Sheet::convert(&write_guard.node)
124 }
125 _ => {
126 let write_guard = get_workspace_lock().write()
127 .expect("Lock poisoned in create() workspace write.");
128 Sheet::convert(&write_guard.node)
129 }
130 }
131 }
132
133 pub fn open(path: &Path) -> Result<Sheet> {
135 let _ = BasePath::init(&path);
136 let write_guard = get_workspace_lock().write()
137 .expect("Lock poisoned in open() workspace write.");
138 Sheet::convert(&write_guard.node)
139 }
140
141 pub fn save() -> Result<()> {
142 let write_guard = get_workspace_lock().write()
144 .expect("Lock poisoned in save() workspace write.");
145 let workflow = write_guard.node.get_workflow()?;
146 if workflow.is_touched() {
147 let mut workspace = write_guard.node.get_workflow_mut()?;
148 workspace.save()?;
149 write_guard.node.set_workflow(workspace);
150 }
151 Ok(())
152 }
153
154 pub fn save_all() -> Result<()> {
155 {
156 let write_guard = get_workspace_lock().write()
157 .expect("Lock poisoned in save_all() workspace write.");
158 let workspace = write_guard.node.get_workflow()?;
159 if workspace.is_touched() {
160 let mut workspace = write_guard.node.get_workflow_mut()?;
161 workspace.save_all()?;
162 write_guard.node.set_workflow(workspace);
163 return Ok(());
164 }
165 }
166 {
167 let read_guard = get_workspace_lock().read()
168 .expect("Lock poisoned in save_all() workspace read.");
169 let workspace = read_guard.node.get_workflow()?;
170 for rule in workspace.iter_rules() {
171 if let Some(node) = rule.get_node() {
172 node.save_all()?;
173 } else if let Some(instance) = rule.get_instance() {
174 instance.save_all()?;
175 }
176 }
177 Ok(())
178 }
179 }
180
181 pub fn compact() -> Result<()> {
183 let read_guard = get_workspace_lock().read()
184 .expect("Lock poisoned in compact() workspace read.");
185 let workspace = read_guard.node.get_workflow()?;
186 for rule in workspace.iter_rules() {
187 if let Some(node) = rule.get_node() {
188 node.compact();
189 } else if let Some(instance) = rule.get_instance() {
190 instance.compact();
191 }
192 }
193 Ok(())
194 }
195
196 pub fn sheet() -> Result<Sheet> {
197 let read_guard = get_workspace_lock().read()
198 .expect("Lock poisoned in sheet() workspace read.");
199 Sheet::convert(&read_guard.node)
200 }
201
202 pub fn catalog() -> Result<Vec<Arc<Sheet>>> {
207 let read_guard = get_workspace_lock().read()
208 .expect("Lock poisoned in catalog() workspace read.");
209 let workspace = read_guard.node.get_workflow_like()?;
210 let mut list = Vec::new();
211 for rule in workspace.iter_rules() {
212 if let Some(node) = rule.get_node() {
213 let sheet = Sheet::convert(&node)?;
214 list.push(Arc::new(sheet));
215 }
216 }
217 Ok(list)
218 }
219
220 pub fn contains_node(identifier: &str) -> Result<bool> {
221 let read_guard = get_workspace_lock().read()
222 .expect("Lock poisoned in contains_node() workspace read.");
223 let workspace = read_guard.node.get_workflow_like()?;
224 Ok(workspace.contains(&identifier))
225 }
226
227 fn arc_identifier(input: &str) -> Result<Arc<str>> {
228 if input == "" {
229 return Err(anyhow!("Empty identifier"));
230 }
231 match parse_identifier(input) {
232 Ok((remain, identifier)) => {
233 if remain == "" {
234 if identifier == "_" {
235 Err(anyhow!("Invalid identifier {}", input))
236 } else {
237 Ok(Arc::from(identifier))
238 }
239 } else {
240 Err(anyhow!("Invalid identifier {}~{}", input, remain))
241 }
242 }
243 Err(e) => Err(anyhow!("Syntax error ({})", e)),
244 }
245 }
246
247 pub fn add_node(identifier: &str, parameters: &str) -> Result<Arc<Reference>> {
248 let arc_identifier = Self::arc_identifier(identifier)?;
249 let node = Node::parse(parameters)?;
250 {
252 let read_guard = get_workspace_lock().read()
253 .expect("Lock poisoned in add_node() workspace read.");
254 let workspace = read_guard.node.get_workflow()?;
255 if workspace.contains(&arc_identifier) {
256 return Err(anyhow!("Workspace node {} already exists", identifier));
257 }
258 }
259 {
261 let write_guard = get_workspace_lock().write()
262 .expect("Lock poisoned in add_node() workspace write.");
263 let mut workspace = write_guard.node.get_workflow_mut()?;
264 let reference = workspace.add_node(arc_identifier, node)?;
265 let _ = workspace.save();
266 write_guard.node.set_workflow(workspace);
267 Ok(reference)
268 }
269 }
270
271 pub fn copy_node(from: Arc<str>, to: Arc<str>) -> Result<()> {
272 {
274 let read_guard = get_workspace_lock().read()
275 .expect("Lock poisoned in copy_node() workspace read.");
276 let workspace = read_guard.node.get_workflow()?;
277 if false == workspace.contains(&from) {
278 return Err(anyhow!("Workspace node {} not found", from));
279 }
280 if workspace.contains(&to) {
281 return Err(anyhow!("Workspace node {} already exists", to));
282 }
283 }
284
285 {
287 let write_guard = get_workspace_lock().write()
288 .expect("Lock poisoned in copy_node() workspace write.");
289 let mut workspace = write_guard.node.get_workflow_mut()?;
290 let from_node = workspace.get_node(&from)?;
291 workspace.copy_node(&from_node, to)?;
292 let _ = workspace.save();
293 write_guard.node.set_workflow(workspace);
294 Ok(())
295 }
296 }
297
298 pub fn get_node(identifier: &str) -> Result<Node> {
299 let read_guard = get_workspace_lock().read()
300 .expect("Lock poisoned in get_node() workspace read.");
301 let workspace = read_guard.node.get_workflow()?;
302 if let Some(rule) = workspace.get_rule(identifier) {
303 if let Some(node) = rule.get_node() {
304 return Ok(node);
305 }
306 }
307 return Err(anyhow!("Workspace node {} not found", identifier))
308 }
309
310 pub fn rename_node(from: &str, to: Arc<str>) -> Result<()> {
311 if from == "context" {
312 return Err(anyhow!("Cannot rename context node"))
313 }
314 {
316 let read_guard = get_workspace_lock().read()
317 .expect("Lock poisoned in rename_node() workspace read.");
318 let workspace = read_guard.node.get_workflow()?;
319 if false == workspace.contains(from) {
320 return Err(anyhow!("Workspace node {} not found", from));
321 }
322 if workspace.contains(&to) {
323 return Err(anyhow!("Workspace node {} already exists", to));
324 }
325 }
326
327 {
329 let write_guard = get_workspace_lock().write()
330 .expect("Lock poisoned in rename_node() workspace write.");
331 let mut workspace = write_guard.node.get_workflow_mut()?;
332 workspace.rename_node(from, to)?;
333 let _ = workspace.save();
334 write_guard.node.set_workflow(workspace);
335 Ok(())
336 }
337 }
338
339 pub fn remove_node(identifier: &str) -> Result<()> {
340 if identifier == "context" {
341 return Err(anyhow!("Cannot remove context node"))
342 }
343 {
345 let read_guard = get_workspace_lock().read()
346 .expect("Lock poisoned in remove_node() workspace read.");
347 let workspace = read_guard.node.get_workflow()?;
348 if false == workspace.contains(identifier) {
349 return Err(anyhow!("Workspace node {} not found", identifier));
350 }
351 }
352
353 {
355 let write_guard = get_workspace_lock().write()
356 .expect("Lock poisoned in remove_node() workspace write.");
357 let mut workspace = write_guard.node.get_workflow_mut()?;
358 workspace.delete_node(identifier)?;
359 let _ = workspace.save();
360 write_guard.node.set_workflow(workspace);
361 Ok(())
362 }
363 }
364
365 pub fn locate_node(locator: &Reference) -> Result<Node> {
371 match locator {
372 Reference::One(one) => {
373 if let Ok(node) = Self::get_node(one) {
375 return Ok(node);
376 }
377 }
378 Reference::Two(one, two) => {
379 if let Ok(node) = Self::get_node(one) {
380 if let Some(rule) = &node.get_workflow()?.get_rule(two) {
381 if let Some(node) = rule.get_node() {
382 return Ok(node);
383 }
384 }
385 }
386 }
387 Reference::Three(one, two, three) => {
388 if let Ok(node) = Self::get_node(one) {
389 if let Some(rule) = &node.get_workflow()?.get_rule(two) {
390 if let Some(node) = rule.get_node() {
391 if let Some(rule) = &node.get_workflow()?.get_rule(three) {
392 if let Some(node) = rule.get_node() {
393 return Ok(node);
394 }
395 }
396 }
397 }
398 }
399 }
400 _ => {}
401 }
402 Err(anyhow!("Node {} not found", locator))
403 }
404
405 pub fn locate_instance(locator: &Reference, identifier: &str) -> Result<Instance> {
407 match locator {
408 Reference::One(one) => {
409 if let Ok(node) = Self::get_node(one) {
411 if let Some(rule) = &node.get_workflow()?.get_rule(identifier) {
412 if let Some(instance) = rule.get_instance() {
413 return Ok(instance);
414 }
415 }
416 }
417 }
418 Reference::Two(one, two) => {
419 if let Ok(node) = Self::get_node(one) {
420 if let Some(rule) = &node.get_workflow()?.get_rule(two) {
421 if let Some(node) = rule.get_node() {
422 if let Some(rule) = &node.get_workflow()?.get_rule(identifier) {
423 if let Some(instance) = rule.get_instance() {
424 return Ok(instance);
425 }
426 }
427 }
428 }
429 }
430 }
431 Reference::Three(one, two, three) => {
432 if let Ok(node) = Self::get_node(one) {
433 if let Some(rule) = &node.get_workflow()?.get_rule(two) {
434 if let Some(node) = rule.get_node() {
435 if let Some(rule) = &node.get_workflow()?.get_rule(three) {
436 if let Some(node) = rule.get_node() {
437 if let Some(rule) = &node.get_workflow()?.get_rule(identifier) {
438 if let Some(instance) = rule.get_instance() {
439 return Ok(instance);
440 }
441 }
442 }
443 }
444 }
445 }
446 }
447 }
448 _ => {}
449 }
450 Err(anyhow!("Instance {} not found", locator))
451 }
452
453 pub fn locate_rule(reference: &Reference) -> Result<Option<Arc<Rule>>> {
455 match reference {
456 Reference::Two(one, two) => {
457 if let Ok(node) = Self::get_node(one) {
459 return Ok(node.get_workflow_like()?.get_rule(two));
460 }
461 }
462 Reference::Three(one, two, three) => {
463 if let Ok(node) = Self::get_node(one) {
465 if let Some(rule) = &node.get_workflow_like()?.get_rule(two) {
466 if let Some(node) = rule.get_node() {
467 return Ok(node.get_workflow_like()?.get_rule(three));
468 }
469 }
470 }
471 }
472 Reference::Four(one, two, three, four) => {
473 if let Ok(node) = Self::get_node(one) {
474 if let Some(rule) = &node.get_workflow_like()?.get_rule(two) {
475 if let Some(node) = rule.get_node() {
476 if let Some(rule) = &node.get_workflow_like()?.get_rule(three) {
477 if let Some(node) = rule.get_node() {
478 return Ok(node.get_workflow_like()?.get_rule(four));
479 }
480 }
481 }
482 }
483 }
484 }
485 _ => {}
486 }
487 Ok(None)
488 }
489}