about summary refs log tree commit diff stats
path: root/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ts/tskm/src/interface/project/handle.rs')
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/project/handle.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/pkgs/by-name/ts/tskm/src/interface/project/handle.rs b/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
new file mode 100644
index 00000000..d1cc0b1e
--- /dev/null
+++ b/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
@@ -0,0 +1,87 @@
+use std::{env, fs::File, io::Write};
+
+use anyhow::{anyhow, Context, Result};
+use log::trace;
+
+use crate::{cli::ProjectCommand, task};
+
+use super::{ProjectDefinition, ProjectList, SortAlphabetically};
+
+/// # Panics
+/// If internal expectations fail.
+///
+/// # Errors
+/// If IO operations fail.
+pub fn handle(command: ProjectCommand) -> Result<()> {
+    match command {
+        ProjectCommand::List => {
+            for project in task::Project::all()? {
+                println!("'{}'", project.to_project_display());
+            }
+        }
+        ProjectCommand::Add {
+            mut new_project_name,
+        } => {
+            let project_file = env::var("TSKM_PROJECT_FILE")
+                .map_err(|err| anyhow!("The `TSKM_PROJECT_FILE` env var is unset: {err}"))?;
+
+            let mut projects_content: ProjectList =
+                serde_json::from_reader(File::open(&project_file).with_context(|| {
+                    format!("Failed to open project file ('{project_file:?}') for reading")
+                })?)?;
+
+            let first = new_project_name.project_segments.remove(0);
+            if let Some(mut definition) = projects_content.0.get_mut(&first) {
+                for segment in new_project_name.project_segments {
+                    if definition.subprojects.contains_key(&segment) {
+                        definition = definition
+                            .subprojects
+                            .get_mut(&segment)
+                            .expect("We checked");
+                    } else {
+                        let new_definition = ProjectDefinition::default();
+                        let output = definition
+                            .subprojects
+                            .insert(segment.clone(), new_definition);
+
+                        assert_eq!(output, None);
+
+                        definition = definition
+                            .subprojects
+                            .get_mut(&segment)
+                            .expect("Was just inserted");
+                    }
+                }
+            } else {
+                let mut orig_definition = ProjectDefinition::default();
+                let mut definition = &mut orig_definition;
+                for segment in new_project_name.project_segments {
+                    trace!("Adding segment: {segment}");
+
+                    let new_definition = ProjectDefinition::default();
+
+                    assert!(definition
+                        .subprojects
+                        .insert(segment.clone(), new_definition)
+                        .is_none());
+
+                    definition = definition
+                        .subprojects
+                        .get_mut(&segment)
+                        .expect("Was just inserted");
+                }
+                assert!(projects_content.0.insert(first, orig_definition).is_none());
+            };
+
+            let mut file = File::create(&project_file).with_context(|| {
+                format!("Failed to open project file ('{project_file:?}') for writing")
+            })?;
+            serde_json::to_writer_pretty(
+                &file,
+                &SortAlphabetically::<ProjectList>(projects_content),
+            )?;
+            writeln!(file)?;
+        }
+    }
+    Ok(())
+}