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: 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, config_path: PathBuf, cli_args: GitMoverCli) -> Config {
47        Config {
48            debug: cli_args.verbose,
49            config_path,
50            cli_args,
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    /// Create a new Config object from the default path
63    /// # Panics
64    /// Panics if the config file can't be opened
65    pub fn new(cli_args: GitMoverCli) -> Config {
66        let config_path = Config::get_config_path();
67        let contents = read_to_string(config_path.clone())
68            .unwrap_or_else(|_| panic!("Unable to open {config_path:?}"));
69        Config::parse_config(&contents, config_path, cli_args)
70    }
71
72    /// Save the config data to the config file
73    /// # Panics
74    /// Panics if the config file can't be created or written to
75    pub fn save(&self) {
76        let config_str = toml::to_string(&self.config_data).expect("Unable to serialize config");
77        let mut file = File::create(&self.config_path).expect("Unable to create config file");
78        file.write_all(config_str.as_bytes())
79            .expect("Unable to write to config file");
80    }
81
82    /// Create a new Config object from a custom path
83    /// # Panics
84    /// Panics if the config file can't be opened
85    pub fn new_from_path(cli_args: GitMoverCli, custom_path: &PathBuf) -> Config {
86        let contents = read_to_string(custom_path.clone())
87            .unwrap_or_else(|_| panic!("Unable to open {custom_path:?}"));
88        Config::parse_config(&contents, custom_path.clone(), cli_args)
89    }
90
91    /// Set the debug value
92    pub fn set_debug(mut self, value: u8) -> Self {
93        self.debug = value;
94        self
95    }
96
97    /// Get the path to the config file
98    /// # Panics
99    /// Panics if the home directory can't be found
100    pub fn get_config_path() -> PathBuf {
101        let home_dir = match home_dir() {
102            Some(path) if !path.as_os_str().is_empty() => Ok(path),
103            _ => Err(()),
104        }
105        .expect("Unable to get your home dir! home::home_dir() isn't working");
106        let config_directory = home_dir.join(".config").join(".git-mover");
107        let config_path = config_directory.join("config.toml");
108        create_dir_all(config_directory).expect("Unable to create config dir");
109        if !config_path.exists() {
110            let mut file = File::create(&config_path).expect("Unable to create config file");
111            file.write_all(b"").expect("Unable to write to config file");
112        }
113        config_path
114    }
115
116    /// Update the config data and save it to the config file
117    pub fn update(&mut self, updater_fn: impl FnOnce(&mut ConfigData) -> &mut ConfigData) {
118        updater_fn(&mut self.config_data);
119        self.save();
120    }
121}