Skip to content

Commit

Permalink
bug fix, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lxl66566 committed May 12, 2024
1 parent f0388a7 commit 6856984
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 146 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ assert2 = "0.3.14"
clap = { version = "4.5.4", features = ["derive"] }
colored = "2.1.0"
compio = { version = "0.10.0", features = ["macros", "dispatcher"] }
const-str = "0.5.7"
die-exit = { version = "0.5.0", features = ["red"] }
enum-tools = "0.5.3"
env_logger = "0.11.3"
Expand Down
4 changes: 4 additions & 0 deletions git_simple_encrypt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
path = "git_simple_encrypt.toml"
use_zstd = true
zstd_level = 15
crypt_list = []
11 changes: 4 additions & 7 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use std::{path::PathBuf, sync::LazyLock as Lazy};
use std::path::PathBuf;

use assert2::assert;
use clap::{Parser, Subcommand};

use crate::{
config::Config,
repo::{GitCommand, Repo},
};
use crate::repo::{GitCommand, Repo};

#[derive(Parser, Clone, Debug)]
#[command(author, version, about, long_about = None, after_help = r#"Examples:
Expand Down Expand Up @@ -45,7 +42,7 @@ pub enum SubCommand {
#[clap(alias("d"))]
Decrypt,
/// Mark files or folders as need-to-be-crypted.
Add { path: Vec<PathBuf> },
Add { path: Vec<String> },
/// Set key or other config items.
Set { field: SetField, value: String },
}
Expand Down Expand Up @@ -76,7 +73,7 @@ impl SetField {
let temp = value.parse::<u8>();
assert!(temp.is_ok(), "value should be a number");
let temp = temp.unwrap();
assert!(temp >= 1 && temp <= 22, "value should be 1-22");
assert!((1..=22).contains(&temp), "value should be 1-22");
repo.conf.zstd_level = temp;
}
};
Expand Down
119 changes: 90 additions & 29 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use std::path::{Path, PathBuf};

use anyhow::Context;
use colored::Colorize;
use die_exit::die;
use serde::{Deserialize, Serialize};

use crate::{
crypt::{COMPRESSED_EXTENSION, ENCRYPTED_EXTENSION},
utils::PathToAbsolute,
};

pub const CONFIG_FILE: &str = concat!(env!("CARGO_CRATE_NAME"), ".toml");

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -34,69 +40,124 @@ impl Config {
Self::default().with_path(path)
}
pub fn load(&self) -> anyhow::Result<Self> {
let content = std::fs::read_to_string(&self.path)?;
let config: Config = toml::from_str(&content)?;
Ok(config)
Self::load_from(&self.path)
}
pub fn load_from(path: impl AsRef<Path>) -> anyhow::Result<Self> {
let path = path.as_ref();
let content = std::fs::read_to_string(path).with_context(|| {
format!("Warning: config not found in `{}`", path.display()).yellow()
})?;
Ok(toml::from_str(&content)?)
}
pub fn save(&self) -> anyhow::Result<()> {
let content = toml::to_string_pretty(self)?;
std::fs::write(&self.path, content)?;
Ok(())
}
pub fn load_or_create(self) -> Self {
let loaded = self.load();
if let Ok(config) = loaded {
config
} else {
eprintln!(
"{}",
format!(
"Warning: config not found in {}, use default...",
self.path.display()
)
.yellow()
);
let config = Self::default();
fn _load_or_create_inner(path: impl AsRef<Path>, loaded: anyhow::Result<Self>) -> Self {
loaded.unwrap_or_else(|e| {
eprintln!("{e}{}", ", use default config...".yellow());
let config = Self::default_with_path(path);
config
.save()
.unwrap_or_else(|e| die!("Failed to save config file: {}", e));
config
}
})
}
pub fn load_or_create(&self) -> Self {
Self::_load_or_create_inner(&self.path, self.load())
}
pub fn load_or_create_from(path: impl AsRef<Path>) -> Self {
Self::_load_or_create_inner(&path, Self::load_from(&path))
}
pub fn add_to_crypt_list_one(&mut self, path: &str) {
let p = Path::new(path);
debug_assert!(p.exists());
assert2::assert!(
!p.is_absolute(),
"Error: `{:?}`. Please use relative path.",
p
);
assert2::assert!(
![ENCRYPTED_EXTENSION, COMPRESSED_EXTENSION].contains(
&p.extension()
.unwrap_or_default()
.to_str()
.unwrap_or_default()
),
"Cannot add file with extension `{}`, `{}`",
ENCRYPTED_EXTENSION,
COMPRESSED_EXTENSION
);
let joined_path = self
.path
.parent()
.expect("parent dir of config file must exist")
.join(path);
debug_assert!(
joined_path.exists(),
"file not exist: `{:?}`, abs: `{:?}`",
joined_path,
joined_path.absolute()
);
println!(
"Add to crypt list: {}",
format!("{:?}", joined_path.absolute()).green()
);
self.crypt_list
.push(path.to_string() + if p.is_dir() { "/**" } else { "" });
}
pub fn add_to_crypt_list(&mut self, paths: &[&str]) {
paths
.into_iter()
.for_each(|x| self.add_to_crypt_list_one(x));
pub fn add_to_crypt_list(&mut self, paths: &[&str]) -> anyhow::Result<()> {
paths.iter().for_each(|x| self.add_to_crypt_list_one(x));
self.save()
}
}

#[cfg(test)]
mod tests {
use std::fs;

use anyhow::Ok;
use temp_testdir::TempDir;

use super::*;

#[test]
fn test_save_load() -> anyhow::Result<()> {
let temp_dir = TempDir::default();
let file_path = temp_dir.join("test");
let config = Config::default_with_path(&file_path);
config.save()?;
assert!(file_path.exists());
let config_load = Config::load_from(file_path);
assert!(config_load.is_ok());
Ok(())
}

#[test]
fn test() -> anyhow::Result<()> {
let temp_dir = TempDir::default();
let mut config = Config::default_with_path(temp_dir.join("test")).load_or_create();
assert!(config == Config::default());
assert!(temp_dir.join("test").exists());
let file_path = temp_dir.join("test");
assert!(!&file_path.exists());
let mut config = Config::load_or_create_from(&file_path);
assert!(config.zstd_level == Config::default().zstd_level);
assert!(&file_path.exists());

fs::create_dir(temp_dir.join("123"));
fs::create_dir(temp_dir.join("123"))?;
config.add_to_crypt_list_one(temp_dir.join("123").as_os_str().to_string_lossy().as_ref());
config.save();
config.save()?;

let config = Config::default_with_path(temp_dir.join("test")).load()?;
let config = Config::default_with_path(&file_path).load()?;
assert!(config.crypt_list[0].ends_with("/**"));
Ok(())
}

#[test]
#[should_panic]
fn test_add_enc_file() {
let temp_dir = TempDir::default();
std::fs::File::create(temp_dir.join("test.enc")).unwrap();
let file_path = temp_dir.join("test");
let mut config = Config::load_or_create_from(file_path);
config.add_to_crypt_list_one("test.enc");
}
}
22 changes: 16 additions & 6 deletions src/crypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use tap::Tap;
#[cfg(any(test, debug_assertions))]
use crate::utils::format_hex;
use crate::{
config::Config,
repo::{GitCommand, Repo},
utils::pathutils::*,
};
Expand Down Expand Up @@ -131,6 +130,8 @@ fn try_decompress(bytes: &[u8], path: PathBuf) -> anyhow::Result<(Vec<u8>, PathB
/// encrypt file, and unlink it.
pub async fn encrypt_file(file: impl AsRef<Path>, repo: &Repo) -> anyhow::Result<PathBuf> {
let file = file.as_ref();
debug!("encrypt_file accept: {:?}", file);
debug_assert!(file.exists());
debug_assert!(file.is_file());
let new_file = file.to_owned();
if is_same_file(file, &repo.conf.path)? {
Expand All @@ -146,7 +147,7 @@ pub async fn encrypt_file(file: impl AsRef<Path>, repo: &Repo) -> anyhow::Result
"Warning: file has been encrypted, do not encrypt.".yellow()
)
}
println!("Encrypting file: `{}`", format!("{:?}", file).green());
println!("Encrypting file: {}", format!("{:?}", file).green());
let bytes = compio::fs::read(file)
.await
.with_context(|| format!("{:?}", file))?;
Expand All @@ -162,7 +163,7 @@ pub async fn encrypt_file(file: impl AsRef<Path>, repo: &Repo) -> anyhow::Result
/// decrypt file, and unlink it.
pub async fn decrypt_file(file: impl AsRef<Path>, repo: &Repo) -> anyhow::Result<PathBuf> {
println!(
"Decrypting file: `{}`",
"Decrypting file: {}",
format!("{:?}", file.as_ref()).green()
);
let new_file = file.as_ref().to_owned();
Expand Down Expand Up @@ -222,9 +223,18 @@ pub async fn decrypt_repo(repo: &Repo) -> anyhow::Result<()> {

#[cfg(test)]
mod test {
use anyhow::Ok;
use same_file::is_same_file;
use temp_testdir::TempDir;
use anyhow::Result;

use super::*;

#[test]
fn test_encrypt_decrypt() -> Result<()> {
let key = b"123456";
let content = b"456789";
let encrypted_content = encrypt(key, content).unwrap();
assert_ne!(content.to_vec(), encrypted_content);
let decrypted_content = decrypt(key, &encrypted_content).unwrap();
assert_eq!(content.to_vec(), decrypted_content);
Ok(())
}
}
14 changes: 5 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(lazy_cell)]
#![feature(vec_pop_if)]
#![feature(let_chains)]
#![feature(absolute_path)]
#![warn(clippy::nursery, clippy::cargo)]
#![allow(clippy::multiple_crate_versions)]

Expand All @@ -15,21 +16,16 @@ use crypt::{decrypt_repo, encrypt_repo};
use repo::Repo;
use utils::{Git2Patch, PathToUnixStyle};

pub use crate::cli::{Cli, SubCommand};
pub use crate::cli::{Cli, SetField, SubCommand};

pub async fn run(cli: &Cli) -> Result<()> {
let mut repo = Repo::open(&cli.repo)?;
match &cli.command {
SubCommand::Encrypt => encrypt_repo(&repo).await?,
SubCommand::Decrypt => decrypt_repo(&repo).await?,
SubCommand::Add { path } => {
let paths_patch = &path
.iter()
.map(|p| p.to_unix_style().patch().to_string_lossy().to_string())
.collect::<Vec<String>>();
repo.conf
.add_to_crypt_list(&paths_patch.iter().map(|s| s.as_ref()).collect::<Vec<_>>())
}
SubCommand::Add { path } => repo
.conf
.add_to_crypt_list(&path.iter().map(|s| s.as_ref()).collect::<Vec<_>>())?,
SubCommand::Set { field, value } => field.set(&mut repo, value)?,
}
Ok(())
Expand Down
Loading

0 comments on commit 6856984

Please sign in to comment.