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, github::config::GithubConfig,
13    gitlab::config::GitlabConfig,
14};
15
16/// Configuration data
17#[derive(Deserialize, Default, Clone, Debug)]
18pub struct Config {
19    /// debug level
20    pub debug: u8,
21
22    /// path to the configuration file
23    pub config_path: PathBuf,
24
25    /// actual configuration data
26    pub config_data: ConfigData,
27
28    /// CLI arguments
29    pub cli_args: Option<GitMoverCli>,
30}
31
32#[derive(Deserialize, Serialize, Default, Clone, Debug)]
33pub struct ConfigData {
34    /// Gitlab configuration
35    pub gitlab: Option<GitlabConfig>,
36
37    /// Github configuration
38    pub github: Option<GithubConfig>,
39
40    /// Codeberg configuration
41    pub codeberg: Option<CodebergConfig>,
42}
43
44impl Config {
45    /// Parse the config file
46    fn parse_config(str_config: &str, path_config: PathBuf) -> Config {
47        Config {
48            debug: 0,
49            config_path: path_config,
50            cli_args: None,
51            config_data: match toml::from_str(str_config) {
52                Ok(config) => config,
53                Err(e) => {
54                    eprintln!("Unable to parse config file: {e}");
55                    eprintln!("Using default config");
56                    ConfigData::default()
57                }
58            },
59        }
60    }
61
62    /// Set the config arguments
63    pub fn with_cli_args(mut self, cli_args: GitMoverCli) -> Self {
64        self.cli_args = Some(cli_args);
65        self
66    }
67
68    /// Create a new Config object from the default path
69    /// # Panics
70    /// Panics if the config file can't be opened
71    pub fn new() -> Config {
72        let config_path = Config::get_config_path();
73        let contents = read_to_string(config_path.clone())
74            .unwrap_or_else(|_| panic!("Unable to open {config_path:?}"));
75        Config::parse_config(&contents, config_path)
76    }
77
78    /// Save the config data to the config file
79    /// # Panics
80    /// Panics if the config file can't be created or written to
81    pub fn save(&self) {
82        let config_str = toml::to_string(&self.config_data).expect("Unable to serialize config");
83        let mut file = File::create(&self.config_path).expect("Unable to create config file");
84        file.write_all(config_str.as_bytes())
85            .expect("Unable to write to config file");
86    }
87
88    /// Create a new Config object from a custom path
89    /// # Panics
90    /// Panics if the config file can't be opened
91    pub fn new_from_path(custom_path: &PathBuf) -> Config {
92        let contents = read_to_string(custom_path.clone())
93            .unwrap_or_else(|_| panic!("Unable to open {custom_path:?}"));
94        Config::parse_config(&contents, custom_path.clone())
95    }
96
97    /// Set the debug value
98    pub fn set_debug(mut self, value: u8) -> Self {
99        self.debug = value;
100        self
101    }
102
103    /// Get the path to the config file
104    /// # Panics
105    /// Panics if the home directory can't be found
106    pub fn get_config_path() -> PathBuf {
107        let home_dir = match home_dir() {
108            Some(path) if !path.as_os_str().is_empty() => Ok(path),
109            _ => Err(()),
110        }
111        .expect("Unable to get your home dir! home::home_dir() isn't working");
112        let config_directory = home_dir.join(".config").join(".git-mover");
113        let config_path = config_directory.join("config.toml");
114        create_dir_all(config_directory).expect("Unable to create config dir");
115        if !config_path.exists() {
116            let mut file = File::create(&config_path).expect("Unable to create config file");
117            file.write_all(b"").expect("Unable to write to config file");
118        }
119        config_path
120    }
121
122    /// Update the config data and save it to the config file
123    pub fn update(&mut self, updater_fn: impl FnOnce(&mut ConfigData) -> &mut ConfigData) {
124        updater_fn(&mut self.config_data);
125        self.save();
126    }
127}