Skip to content

Commit

Permalink
Simplify config file format
Browse files Browse the repository at this point in the history
  • Loading branch information
kkocdko committed Apr 10, 2022
1 parent 1cb8893 commit b0cbc6a
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 100 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Run Tests
run: cargo test

- name: Show Toolchain Info
run: rustup toolchain list && rustup target list --installed

- name: Run Build
- name: Test
run: cargo test

- name: Build
run: cargo build --release

- name: Upload Artifacts
Expand Down
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "clevert"
description = "Extensible file converter."
version = "0.8.1"
version = "0.9.0"
edition = "2021"
license = "MIT"

Expand All @@ -18,4 +18,6 @@ shared_child = "1.0.0"
toml = "0.5.8"
yansi = "0.5.1"
# tiny_http = "0.11.0"
# vc-ltl = "5.0.4"

[target.x86_64-pc-windows-msvc.dependencies]
vc-ltl = "5.0.4"
90 changes: 41 additions & 49 deletions src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Action {

// execute error or no-zero exit
Err(e) => {
let _ = self.stop(); // make other threads to stop
self.stop().ok(); // make other threads to stop
self.status.lock().unwrap().result = Err(Arc::new(e));
break;
}
Expand Down Expand Up @@ -137,51 +137,41 @@ impl Action {
}

pub fn new(cfg: &Config) -> Result<Arc<Self>, Error> {
fn visit_dir(dir: PathBuf, recursive: bool) -> io::Result<Vec<PathBuf>> {
fn visit_dir(dir: PathBuf) -> io::Result<Vec<PathBuf>> {
let mut ret = Vec::new();
for item in fs::read_dir(dir)? {
let item = item?.path();
if item.is_file() {
ret.push(item);
} else if recursive && item.is_dir() {
ret.append(&mut visit_dir(item, recursive)?);
} else if item.is_dir() {
ret.append(&mut visit_dir(item)?);
}
}
Ok(ret)
}
let read_dir = |dir| {
let recursive = cfg.input_recursive.unwrap();
let ret = visit_dir(dir, recursive).map_err(|e| Error {
kind: ErrorKind::Config,
message: "read input dir failed".to_string(),
inner: Box::new(e),
})?;
Ok(ret)
};
let mut input_files = Vec::new();
if let Some(input_list) = &cfg.input_list {
for item in input_list {
let path = PathBuf::from(item);
if path.is_file() {
input_files.push(path);
} else {
input_files.append(&mut read_dir(path)?);
}
for item in cfg.input_list.as_ref().unwrap() {
let path = PathBuf::from(item);
if path.is_dir() {
input_files.append(&mut visit_dir(path).map_err(|e| Error {
kind: ErrorKind::Config,
message: "read input items failed".to_string(),
inner: Box::new(e),
})?);
} else {
input_files.push(path);
}
} else if let Some(input_dir) = &cfg.input_dir {
let input_dir = PathBuf::from(input_dir);
input_files.append(&mut read_dir(input_dir)?);
}

// Current dir is different with exe dir
// current dir is different with exe dir
let current_dir = env::current_dir().unwrap();
let mut pairs = Vec::new(); // (from, to)
for mut input_file in input_files {
// Bare name
let file_name = input_file.file_stem().unwrap().to_str().unwrap();
let mut file_name = file_name.to_string();
// stem name
let file_name = input_file.file_stem().unwrap();
let mut file_name = file_name.to_str().unwrap().to_string();

// Set prefix and suffix
// prefix and suffix
if let Some(prefix) = &cfg.output_prefix {
file_name.insert_str(0, prefix);
}
Expand All @@ -194,40 +184,48 @@ impl Action {
None => input_file.parent().unwrap().into(),
};

// Keep output recursive directories structure
if cfg.output_recursive.unwrap() && cfg.input_dir.is_some() {
let input_dir = cfg.input_dir.as_ref().unwrap();
// keep output recursive dirs structure
if !cfg.output_recursive.unwrap() {
output_file.push(file_name);
} else if cfg.input_list.as_ref().unwrap().len() == 1 {
let input_dir = cfg.input_list.as_ref().unwrap()[0].clone();
let relative_path = input_file.strip_prefix(input_dir).unwrap();
output_file.push(relative_path);
output_file.set_file_name(file_name);
let output_dir = output_file.parent().unwrap();
fs::create_dir_all(output_dir).unwrap();
} else {
output_file.push(file_name);
return Err(Error {
kind: ErrorKind::Config,
message: "input_list must contain only 1 item when output_recursive"
.to_string(),
..Default::default()
});
}

// Set extension name
// extension
if let Some(extension) = &cfg.output_extension {
output_file.set_extension(extension);
} else if let Some(extension) = input_file.extension() {
output_file.set_extension(extension);
}

// Expand repative path to absolute
// expand repative path to absolute
if cfg.input_absolute.unwrap() && !input_file.is_absolute() {
input_file = current_dir.join(&input_file);
}
if cfg.output_absolute.unwrap() && !output_file.is_absolute() {
output_file = current_dir.join(&output_file);
}

// Overwrite
if cfg.output_overwrite.unwrap() {
// force overwrite
if cfg.output_force.unwrap() {
// TODO: if-let-chain after rust 1.62
if let Err(e) = fs::remove_file(&output_file) {
if e.kind() != io::ErrorKind::NotFound {
return Err(Error {
kind: ErrorKind::Config,
message: "remove file for output_overwrite failed".to_string(),
message: "remove file for output_force failed".to_string(),
inner: Box::new(e),
});
}
Expand Down Expand Up @@ -262,17 +260,11 @@ impl Action {
for part in &args_template {
match *part {
"{input_file}" => command.arg(&input_file),
"{output_file}" if cfg.output_suffix_serial.unwrap() => {
let mut name = String::new();
if let Some(stem) = output_file.file_stem() {
name.push_str(&stem.to_string_lossy());
name.push('_');
}
name.push_str(&repeat_num.to_string());
if let Some(ext) = output_file.extension() {
name.push('.');
name.push_str(&ext.to_string_lossy());
}
"{output_file}" if cfg.output_serial.unwrap() => {
let name = output_file.file_name().unwrap();
let mut name = name.to_str().unwrap().to_string();
let idx = output_file.file_stem().unwrap().len();
name.insert_str(idx, &format!("_{repeat_num}"));
command.arg(output_file.with_file_name(name))
}
"{output_file}" => command.arg(&output_file),
Expand Down
34 changes: 14 additions & 20 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,18 @@ pub struct Config {
pub repeat_count: Option<usize>,
pub pipe: Option<String>,
pub program: Option<String>,
pub current_dir: Option<String>,
pub args_template: Option<String>,
pub current_dir: Option<String>,
pub input_list: Option<Vec<String>>,
pub input_dir: Option<String>,
pub input_absolute: Option<bool>,
pub input_recursive: Option<bool>,
pub output_dir: Option<String>,
pub output_absolute: Option<bool>,
pub output_recursive: Option<bool>,
pub output_overwrite: Option<bool>,
pub output_extension: Option<String>,
pub output_recursive: Option<bool>,
pub output_force: Option<bool>,
pub output_prefix: Option<String>,
pub output_suffix: Option<String>,
pub output_suffix_serial: Option<bool>,
pub output_serial: Option<bool>,
}

impl Default for Config {
Expand All @@ -35,22 +33,20 @@ impl Default for Config {
threads_count: Some(num_cpus::get()),
ignore_panic: Some(false),
repeat_count: Some(1),
pipe: None, // None | <inherit> | path,
pipe: None, // None | <inherit> | path
program: None,
current_dir: None, // only apply on commands, has no effect to self
args_template: Some(String::new()),
input_list: None,
input_dir: None,
current_dir: None, // only apply on commands, has no effect to self
input_list: Some(Vec::new()),
input_absolute: Some(false),
input_recursive: Some(false),
output_dir: None,
output_absolute: Some(false),
output_recursive: Some(false),
output_overwrite: Some(false),
output_extension: None,
output_recursive: Some(false),
output_force: Some(false),
output_prefix: None,
output_suffix: None,
output_suffix_serial: Some(false),
output_serial: Some(false),
}
}
}
Expand All @@ -74,20 +70,18 @@ impl Config {
repeat_count,
pipe,
program,
current_dir,
args_template,
current_dir,
input_list,
input_dir,
input_absolute,
input_recursive,
output_dir,
output_absolute,
output_recursive,
output_overwrite,
output_extension,
output_recursive,
output_force,
output_prefix,
output_suffix,
output_suffix_serial
output_serial
);
}
}
Expand Down
28 changes: 15 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,24 @@ fn run() -> Result<(), Error> {
// const HELP_TEXT: &str = r#"Usage: clevert [input_items]"#;

fn main() {
// https://github.com/SergioBenitez/yansi/issues/25
#[cfg(windows)]
if !yansi::Paint::enable_windows_ascii() {
yansi::Paint::disable()
{
// https://github.com/SergioBenitez/yansi/issues/25
if !yansi::Paint::enable_windows_ascii() {
yansi::Paint::disable()
}
// linux x11?
if env::var("PROMPT").is_err() {
// manually panic handling, because the `catch_unwind` is not always
// stable and it's inapplicable when panic='abort'
let mut cmd = Command::new(env::current_exe().unwrap());
let _ = cmd.args(env::args().skip(1)).env("PROMPT", "$P$G").status();
log!("press <enter> key to exit");
io::stdin().read_line(&mut String::new()).unwrap();
return;
}
}

#[cfg(windows)] // linux x11?
if env::var("PROMPT").is_err() {
// manually panic handling, because the `catch_unwind` is not always
// stable and it's inapplicable when panic='abort'
let mut cmd = Command::new(env::current_exe().unwrap());
let _ = cmd.args(env::args().skip(1)).env("PROMPT", "$P$G").status();
log!("press <enter> key to exit");
io::stdin().read_line(&mut String::new()).unwrap();
return;
}
if let Err(e) = run() {
log!(error:"error = {:?}",e);
}
Expand Down
20 changes: 8 additions & 12 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{Action, Profile};
use std::fs;
use std::io;
use std::path::PathBuf;
use std::process::Command;
use std::sync::Arc;
Expand All @@ -9,16 +8,15 @@ use std::thread;
#[test]
pub fn common() -> Result<(), Box<dyn std::error::Error>> {
let dir = PathBuf::from("./target/_test");
fs::remove_dir_all(&dir).ok(); // Ignore error when dir not exists
let _ = fs::remove_dir_all(&dir); // ignore error when dir not exists
fs::create_dir_all(dir.join("input"))?;
for i in 0..4 {
fs::write(dir.join("input").join(i.to_string()), "")?;
}
fs::write(dir.join("sleeper.rs"), SLEEPER_SRC)?;
Command::new("rustc")
.arg("-o")
.arg(dir.join("sleeper"))
.arg(dir.join("sleeper.rs"))
.current_dir(&dir) // do not pollute project dir
.args(["-o", "sleeper", "sleeper.rs"])
.status()?;
let profile = Profile::from_toml(CFG_TOML)?;
let action = Action::new(&profile.get_current()?)?;
Expand All @@ -28,11 +26,9 @@ pub fn common() -> Result<(), Box<dyn std::error::Error>> {
move || action.wait()
});
action.wait()?;
let read_log_sum = |name| -> io::Result<u8> {
let content = fs::read(dir.join(name))?;
Ok(content.iter().map(|ch| ch - '0' as u8).sum())
};
assert_eq!(read_log_sum("pipe.txt")?, 24);
drop(action); // drop file handlers also
let piped = fs::read_to_string(dir.join("pipe.txt"))?;
assert_eq!(piped.matches('1').count(), 24);
Ok(())
}

Expand All @@ -46,7 +42,7 @@ ignore_panic = false
[presets.test_base]
repeat_count = 6
input_dir = './target/_test/input'
input_list = ['./target/_test/input']
output_dir = './target/_test/output'
pipe = '<inherit>'
Expand All @@ -60,7 +56,7 @@ pipe = './target/_test/pipe.txt'
const SLEEPER_SRC: &str = r#"
fn main() {
let r = std::env::args().last().unwrap().parse::<u64>().unwrap() % 2;
std::thread::sleep(std::time::Duration::from_millis(r * 25 + 50));
std::thread::sleep(std::time::Duration::from_millis(r * 29 + 53));
print!("{}", r);
eprint!("{}", r);
}
Expand Down

0 comments on commit b0cbc6a

Please sign in to comment.