summaryrefslogtreecommitdiff
path: root/crates/vcs_data/src/data/local.rs
blob: 96080b2cab180ab8ea436a20f0c3281e66a18dc2 (plain)
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
88
89
90
91
92
93
94
95
96
97
use std::{env::current_dir, path::PathBuf, sync::Arc};

use cfg_file::config::ConfigFile;
use tokio::{fs, sync::Mutex};
use vcs_docs::docs::READMES_LOCAL_WORKSPACE_TODOLIST;

use crate::{
    constants::{CLIENT_FILE_TODOLIST, CLIENT_FILE_WORKSPACE},
    current::{current_local_path, find_local_path},
    data::local::config::LocalConfig,
};

pub mod cached_sheet;
pub mod config;
pub mod latest_info;
pub mod local_sheet;
pub mod member_held;

pub struct LocalWorkspace {
    config: Arc<Mutex<LocalConfig>>,
    local_path: PathBuf,
}

impl LocalWorkspace {
    /// Get the path of the local workspace.
    pub fn local_path(&self) -> &PathBuf {
        &self.local_path
    }

    /// Initialize local workspace.
    pub fn init(config: LocalConfig, local_path: impl Into<PathBuf>) -> Option<Self> {
        let local_path = find_local_path(local_path)?;
        Some(Self {
            config: Arc::new(Mutex::new(config)),
            local_path,
        })
    }

    /// Initialize local workspace in the current directory.
    pub fn init_current_dir(config: LocalConfig) -> Option<Self> {
        let local_path = current_local_path()?;
        Some(Self {
            config: Arc::new(Mutex::new(config)),
            local_path,
        })
    }

    /// Setup local workspace
    pub async fn setup_local_workspace(
        local_path: impl Into<PathBuf>,
    ) -> Result<(), std::io::Error> {
        let local_path: PathBuf = local_path.into();

        // Ensure directory is empty
        if local_path.exists() && local_path.read_dir()?.next().is_some() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::DirectoryNotEmpty,
                "DirectoryNotEmpty",
            ));
        }

        // 1. Setup config
        let config = LocalConfig::default();
        LocalConfig::write_to(&config, local_path.join(CLIENT_FILE_WORKSPACE)).await?;

        // 2. Setup README.md
        let readme_content = READMES_LOCAL_WORKSPACE_TODOLIST.trim().to_string();
        fs::write(local_path.join(CLIENT_FILE_TODOLIST), readme_content).await?;

        // On Windows, set the .jv directory as hidden
        #[cfg(target_os = "windows")]
        {
            use std::os::windows::fs::MetadataExt;
            use winapi_util::file::set_hidden;

            let jv_dir = local_path.join(".jv");
            if jv_dir.exists() {
                if let Err(e) = set_hidden(&jv_dir, true) {
                    eprintln!("Warning: Failed to set .jv directory as hidden: {}", e);
                }
            }
        }

        Ok(())
    }

    /// Get a reference to the local configuration.
    pub fn config(&self) -> Arc<Mutex<LocalConfig>> {
        self.config.clone()
    }

    /// Setup local workspace in current directory
    pub async fn setup_local_workspace_current_dir() -> Result<(), std::io::Error> {
        Self::setup_local_workspace(current_dir()?).await?;
        Ok(())
    }
}