git_mover/
config.rs

1//! Configuration handling
2use std::{
3    fs::{create_dir_all, read_to_string, File},
4    io::Write,
5    path::PathBuf,
6};
7
8use home::home_dir;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12    cli::GitMoverCli, codeberg::config::CodebergConfig, errors::GitMoverError,
13    github::config::GithubConfig, gitlab::config::GitlabConfig,
14};
15
16/// Configuration data
17#[derive(Deserialize, Default, Clone, Debug)]
18pub struct GitMoverConfig {
19    /// path to the configuration file
20    pub config_path: PathBuf,
21
22    /// actual configuration data
23    pub config_data: ConfigData,
24
25    /// CLI arguments
26    pub cli_args: GitMoverCli,
27}
28
29#[derive(Deserialize, Serialize, Default, Clone, Debug)]
30pub struct ConfigData {
31    /// Gitlab configuration
32    pub gitlab: Option<GitlabConfig>,
33
34    /// Github configuration
35    pub github: Option<GithubConfig>,
36
37    /// Codeberg configuration
38    pub codeberg: Option<CodebergConfig>,
39}
40
41impl GitMoverConfig {
42    /// Create a new Config object from the default path
43    /// # Errors
44    /// Error if the config file can't be opened
45    pub fn try_new(cli_args: GitMoverCli) -> Result<Self, GitMoverError> {
46        let config_path = match cli_args.config.clone() {
47            Some(p) => p,
48            None => Self::get_config_path()?,
49        };
50        let contents = read_to_string(config_path.clone())
51            .map_err(|e| GitMoverError::new_with_source("Unable to open", e))?;
52        let config_data = toml::from_str(&contents)?;
53        Ok(GitMoverConfig {
54            config_path,
55            cli_args,
56            config_data,
57        })
58    }
59
60    /// Save the config data to the config file
61    /// # Errors
62    /// Error if the config file can't be created or written to
63    pub fn save(&self) -> Result<(), GitMoverError> {
64        let config_str = toml::to_string(&self.config_data)
65            .map_err(|e| GitMoverError::new_with_source("Unable to serialize config", e))?;
66        let mut file = File::create(&self.config_path)
67            .map_err(|e| GitMoverError::new_with_source("Unable to create config file", e))?;
68        file.write_all(config_str.as_bytes())
69            .map_err(|e| GitMoverError::new_with_source("Unable to write to config file", e))
70    }
71
72    /// Get the path to the config file
73    /// # Errors
74    /// Error if the home directory can't be found
75    pub fn get_config_path() -> Result<PathBuf, GitMoverError> {
76        let home_dir = match home_dir() {
77            Some(path) if !path.as_os_str().is_empty() => path,
78            _ => return Err("Unable to get your home dir! home::home_dir() isn't working".into()),
79        };
80        let config_directory = home_dir.join(".config").join(".git-mover");
81        let config_path = config_directory.join("config.toml");
82        create_dir_all(config_directory)
83            .map_err(|e| GitMoverError::new_with_source("Unable to create config dir", e))?;
84        if !config_path.exists() {
85            let mut file = File::create(&config_path)
86                .map_err(|e| GitMoverError::new_with_source("Unable to create config file", e))?;
87            file.write_all(b"")
88                .map_err(|e| GitMoverError::new_with_source("Unable to write to config file", e))?;
89        }
90        Ok(config_path)
91    }
92
93    /// Update the config data and save it to the config file
94    /// # Errors
95    /// Error if fail to save config
96    pub fn update(
97        &mut self,
98        updater_fn: impl FnOnce(&mut ConfigData),
99    ) -> Result<(), GitMoverError> {
100        updater_fn(&mut self.config_data);
101        self.save()?;
102        Ok(())
103    }
104}