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 #[must_use]
60 pub fn with_repo_path(mut self, path: impl AsRef<Path>) -> Self {
61 let path = path.as_ref();
62 self.repo_path = path.to_path_buf();
63 self.config_path = path.join(CONFIG_FILE_NAME);
64 self
65 }
66
67 pub fn add_one_path_to_crypt_list(&mut self, path: impl AsRef<Path>) -> Result<()> {
73 let path = path
74 .as_ref()
75 .absolutize_from(&self.repo_path)
76 .map_err(|e| Error::Other(format!("path absolutize failed: {e}")))?;
77 debug!("adding path to crypt list: {}", path.display());
78 if !path.exists() {
79 return Err(Error::PathNotExist(path.into_owned()));
80 }
81 let path_relative_to_repo = diff_paths(path.as_ref(), &self.repo_path)
82 .unwrap_or_else(|| path.to_path_buf())
83 .fuck_backslash();
84 debug!(
85 "path diff: {} to {}",
86 path.display(),
87 self.repo_path.display()
88 );
89 if path_relative_to_repo.is_absolute() {
90 return Err(Error::PathNotRelative(path_relative_to_repo));
91 }
92 info!(
93 "Add to encrypt list: {}",
94 path_relative_to_repo.display().to_string().green()
95 );
96 self.crypt_list
97 .push(path_relative_to_repo.to_string_lossy().into_owned());
98 Ok(())
99 }
100
101 pub fn add_paths_to_crypt_list(&mut self, paths: &[impl AsRef<Path>]) -> Result<()> {
104 for x in paths {
105 self.add_one_path_to_crypt_list(x.as_ref())?;
106 }
107 debug!("store config to {}", self.config_path.display());
108 self.store().map_err(|e| Error::Config(e.to_string()))
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use std::{assert, fs};
115
116 use config_file2::LoadConfigFile;
117 use tempfile::TempDir;
118
119 use super::*;
120
121 #[test]
122 fn test_add_one_file_to_crypt_list() -> crate::Result<()> {
123 let temp_dir = TempDir::new()?.keep();
124 let file_path = temp_dir.join("test.toml");
125 let mut config = Config::load_or_default(file_path)
126 .map_err(|e| Error::Config(e.to_string()))?
127 .with_repo_path(&*temp_dir);
128
129 let path_to_add = temp_dir.join("testdir");
130 fs::create_dir(&path_to_add)?;
131 config.add_one_path_to_crypt_list(path_to_add.as_os_str().to_string_lossy().as_ref())?;
132 println!("{:?}", config.crypt_list.first().unwrap());
133 assert!(
134 config
135 .repo_path
136 .join(config.crypt_list.first().unwrap())
137 .is_dir(),
138 "needs to be dir: {}",
139 config.crypt_list.first().unwrap()
140 );
141 Ok(())
142 }
143}