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
use crate::{parse_workspace_name, ExtrasError};
use serde::{Deserialize, Serialize};
use std::{fs::File, io::BufReader, path::Path};
use tfc_toolset::{error::ToolError, workspace::Attributes};

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Workspace {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub attributes: Option<Attributes>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WorkspacesFile {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub workspaces: Option<Vec<Workspace>>,
}

impl From<Vec<tfc_toolset::workspace::Workspace>> for WorkspacesFile {
    fn from(workspaces: Vec<tfc_toolset::workspace::Workspace>) -> Self {
        let mut workspaces_file = WorkspacesFile { workspaces: None };
        let mut workspaces_vec = Vec::new();
        for workspace in workspaces {
            let entry = Workspace {
                name: None,
                id: Some(workspace.id),
                attributes: Some(workspace.attributes),
            };
            workspaces_vec.push(entry);
        }
        workspaces_file.workspaces = Some(workspaces_vec);
        workspaces_file
    }
}

impl WorkspacesFile {
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, ExtrasError> {
        let file = File::open(path).map_err(ToolError::Io)?;
        let reader = BufReader::new(file);
        let workspaces_file: Self =
            serde_json::from_reader(reader).map_err(ToolError::Json)?;
        if let Some(workspaces) = workspaces_file.clone().workspaces {
            for workspace in workspaces {
                if workspace.name.is_none() && workspace.id.is_none() {
                    return Err(ExtrasError::InvalidWorkspacesFile);
                }
                if let Some(name) = workspace.name {
                    parse_workspace_name(&name)?;
                }
            }
        }
        Ok(workspaces_file)
    }

    pub fn save<P: AsRef<Path>>(
        &self,
        path: P,
        pretty: bool,
    ) -> Result<(), ToolError> {
        if pretty {
            serde_json::to_writer_pretty(&File::create(path)?, self)?;
        } else {
            serde_json::to_writer(&File::create(path)?, self)?;
        }
        Ok(())
    }
}