Skip to content

Commit

Permalink
feat(cli): support optional paths to write content to
Browse files Browse the repository at this point in the history
  • Loading branch information
loichyan committed May 12, 2023
1 parent de01928 commit 1cf5989
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 20 deletions.
29 changes: 23 additions & 6 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use std::{path::PathBuf, str::FromStr};
use thisctx::IntoError;

const V_PATH: &str = "PATH";
const V_CLASSES: &str = "CLASSES";
const V_SOURCE: &str = "SOURCE";
const V_CLASSES: &str = "FROM,TO";
const V_FORMAT: &str = "FORMAT";
const CACHE_VERSION: &str = include_str!("cache-version");
const CLAP_LONG_VERSION: &str =
Expand Down Expand Up @@ -47,10 +48,10 @@ pub enum Command {
},
/// Fix obsolete icons interactively.
Fix {
/// Deprecated. Use '-w/--write' instead.
/// Deprecated. Use `-w/--write` instead.
#[arg(short, long)]
yes: bool,
/// Write contents without confirmation.
/// Write content without confirmation.
#[arg(short, long)]
write: bool,
/// Select the first (and most similar) one for all suggestions.
Expand All @@ -65,9 +66,12 @@ pub enum Command {
/// Recursively traverse all directories.
#[arg(short, long)]
recursive: bool,
/// Path(s) of files to check.
#[arg(value_name(V_PATH))]
source: Vec<PathBuf>,
/// Path tuple(s) of files to read from and write to.
///
/// Each tuple is an input path followed by an optional output path, e.g.
/// `/input/as/ouput /read/from:/write/to`.
#[arg(value_name(V_SOURCE))]
source: Vec<Source>,
},
/// Fuzzy search for an icon.
Search {},
Expand Down Expand Up @@ -130,3 +134,16 @@ pub enum OutputFormat {
#[value(help("Human-readable output format"))]
Console,
}

#[derive(Clone, Debug)]
pub struct Source(pub PathBuf, pub Option<PathBuf>);

impl FromStr for Source {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(s.split_once(':')
.map(|(input, output)| Source(input.into(), Some(output.into())))
.unwrap_or_else(|| Source(s.into(), None)))
}
}
48 changes: 34 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ mod runtime;
shadow_rs::shadow!(shadow);

use clap::Parser;
use cli::Command;
use cli::{Command, Source};
use prompt::YesOrNo;
use runtime::{CheckerContext, Runtime};
use std::path::PathBuf;
use thisctx::WithContext;
use tracing::{error, warn, Level};
use util::ResultExt;
Expand All @@ -23,18 +22,37 @@ use walkdir::WalkDir;
static CACHED: &str = include_str!("./cached.txt");

fn walk<'a>(
paths: impl 'a + IntoIterator<Item = PathBuf>,
paths: impl 'a + IntoIterator<Item = Source>,
recursive: bool,
) -> impl 'a + Iterator<Item = error::Result<PathBuf>> {
) -> impl 'a + Iterator<Item = error::Result<Source>> {
if !recursive {
Box::new(paths.into_iter().map(Ok)) as Box<dyn Iterator<Item = _>>
} else {
Box::new(
paths
.into_iter()
.flat_map(WalkDir::new)
.map(|entry| Ok(entry?.into_path()))
.filter(|p| if let Ok(p) = p { p.is_file() } else { true }),
.flat_map(|Source(input, output)| {
if let Some(output) = output {
warn!(
"Output path is ignored when '--recursive': {}",
output.display()
);
}

WalkDir::new(input)
})
.filter_map(|entry| {
tryb! {
let path = entry?.into_path();
if path.is_file() {
Ok(Some(path))
} else {
Ok(None)
}
}
.transpose()
})
.map(|e| e.map(|path| Source(path, None))),
)
}
}
Expand Down Expand Up @@ -75,9 +93,10 @@ fn main_impl() -> error::Result<()> {
format,
..Default::default()
};
for path in walk(source, recursive) {
for source in walk(source.into_iter().map(|p| Source(p, None)), recursive) {
tryb! {
rt.check(&mut context, &path?, false)
let source = source?;
rt.check(&mut context, &source.0, false)
}
.ignore_interrupted()
.log_error();
Expand All @@ -100,11 +119,12 @@ fn main_impl() -> error::Result<()> {
select_first,
..Default::default()
};
for path in walk(source, recursive) {
for source in walk(source, recursive) {
tryb! {
let path = path?;
let path = &path;
if let Some(patched) = rt.check(&mut context, path, true)? {
let source = source?;
let Source(input, output) = &source;
let output = output.as_ref().unwrap_or(input);
if let Some(patched) = rt.check(&mut context, input, true)? {
if !context.write {
match prompt::prompt_yes_or_no(
"Are your sure to write the patched content?",
Expand All @@ -115,7 +135,7 @@ fn main_impl() -> error::Result<()> {
_ => {}
}
}
std::fs::write(path, patched).context(error::Io(path))?;
std::fs::write(output, patched).context(error::Io(output))?;
}
Ok(())
}
Expand Down

0 comments on commit 1cf5989

Please sign in to comment.