about summary refs log tree commit diff stats
path: root/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
blob: 2b01f5d1e29a2e2b8271a0fd5524a32f6ef745ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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(())
}