git_simple_encrypt/
config.rs1use std::path::{Path, PathBuf};
2
3use config_file2::Storable;
4use fuck_backslash::FuckBackslash;
5use log::{debug, info};
6use path_absolutize::Absolutize as _;
7use pathdiff::diff_paths;
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 error::{Error, Result},
12 utils::style::Colorize,
13};
14
15pub const CONFIG_FILE_NAME: &str = concat!(env!("CARGO_CRATE_NAME"), ".toml");
16
17#[allow(clippy::struct_field_names)]
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct Config {
20 #[serde(skip)]
23 pub repo_path: PathBuf,
24 #[serde(skip)]
26 pub(crate) config_path: PathBuf,
27 pub use_zstd: bool,
29 pub zstd_level: u8,
31 pub crypt_list: Vec<String>,
33}
34
35impl Default for Config {
36 fn default() -> Self {
37 Self {
38 repo_path: PathBuf::from("."),
39 config_path: PathBuf::from(CONFIG_FILE_NAME),
40 use_zstd: true,
41 zstd_level: 15,
42 crypt_list: vec![],
43 }
44 }
45}
46
47impl Storable for Config {
48 fn path(&self) -> impl AsRef<Path> {
49 &self.config_path
50 }
51}
52
53impl Config {
54 pub fn new(path: impl AsRef<Path>) -> Self {
56 Self::default().with_repo_path(path)
57 }
58
59 #[must_use]
61 pub fn with_repo_path(mut self, path: impl AsRef<Path>) -> Self {
62 let path = path.as_ref();
63 self.repo_path = path.to_path_buf();
64 self.config_path = path.join(CONFIG_FILE_NAME);
65 self
66 }
67
68 pub fn add_one_path_to_crypt_list(&mut self, path: impl AsRef<Path>) -> Result<()> {
74 let path = path.as_ref().absolutize_from(&self.repo_path);
75 debug!("adding path to crypt list: {}", path.display());
76 if !path.exists() {
77 return Err(Error::PathNotExist(path.into_owned()));
78 }
79 let path_relative_to_repo = diff_paths(path.as_ref(), &self.repo_path)
80 .unwrap_or_else(|| path.to_path_buf())
81 .fuck_backslash();
82 debug!(
83 "path diff: {} to {}",
84 path.display(),
85 self.repo_path.display()
86 );
87 if path_relative_to_repo.is_absolute() {
88 return Err(Error::PathNotRelative(path_relative_to_repo));
89 }
90 info!(
91 "Add to encrypt list: {}",
92 path_relative_to_repo.display().to_string().green()
93 );
94 self.crypt_list
95 .push(path_relative_to_repo.to_string_lossy().into_owned());
96 Ok(())
97 }
98
99 pub fn add_paths_to_crypt_list(&mut self, paths: &[impl AsRef<Path>]) -> Result<()> {
102 for x in paths {
103 self.add_one_path_to_crypt_list(x.as_ref())?;
104 }
105 debug!("store config to {}", self.config_path.display());
106 self.save().map_err(|e| Error::Config(e.to_string()))
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use std::{assert, fs};
113
114 use config_file2::LoadConfigFile;
115 use tempfile::TempDir;
116
117 use super::*;
118
119 #[test]
120 fn test_add_one_file_to_crypt_list() -> Result<()> {
121 let temp_dir = TempDir::new()?.keep();
122 let file_path = temp_dir.join("test.toml");
123 let mut config = Config::load_or_default(file_path)
124 .map_err(|e| Error::Config(e.to_string()))?
125 .with_repo_path(&*temp_dir);
126
127 let path_to_add = temp_dir.join("testdir");
128 fs::create_dir(&path_to_add)?;
129 config.add_one_path_to_crypt_list(path_to_add.as_os_str().to_string_lossy().as_ref())?;
130 println!("{:?}", config.crypt_list.first().unwrap());
131 assert!(
132 config
133 .repo_path
134 .join(config.crypt_list.first().unwrap())
135 .is_dir(),
136 "needs to be dir: {}",
137 config.crypt_list.first().unwrap()
138 );
139 Ok(())
140 }
141}