parent
f71931838c
commit
26cc6a13b4
|
@ -1,15 +1,16 @@
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{BufRead, BufReader, Read},
|
io::{stdout, BufRead, BufReader, Read, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use argp::FromArgs;
|
use argp::FromArgs;
|
||||||
use owo_colors::{OwoColorize, Stream};
|
use owo_colors::{OwoColorize, Stream};
|
||||||
|
use path_slash::PathExt;
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
use crate::util::file::{open_file, process_rsp, touch};
|
use crate::util::file::{buf_writer, open_file, process_rsp, touch};
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Print or check SHA1 (160-bit) checksums.
|
/// Print or check SHA1 (160-bit) checksums.
|
||||||
|
@ -22,7 +23,8 @@ pub struct Args {
|
||||||
/// path to input file(s)
|
/// path to input file(s)
|
||||||
files: Vec<PathBuf>,
|
files: Vec<PathBuf>,
|
||||||
#[argp(option, short = 'o')]
|
#[argp(option, short = 'o')]
|
||||||
/// touch output file on successful check
|
/// (check) touch output file on successful check
|
||||||
|
/// (hash) write hash(es) to output file
|
||||||
output: Option<PathBuf>,
|
output: Option<PathBuf>,
|
||||||
#[argp(switch, short = 'q')]
|
#[argp(switch, short = 'q')]
|
||||||
/// only print failures and a summary
|
/// only print failures and a summary
|
||||||
|
@ -32,17 +34,28 @@ pub struct Args {
|
||||||
const DEFAULT_BUF_SIZE: usize = 8192;
|
const DEFAULT_BUF_SIZE: usize = 8192;
|
||||||
|
|
||||||
pub fn run(args: Args) -> Result<()> {
|
pub fn run(args: Args) -> Result<()> {
|
||||||
for path in process_rsp(&args.files)? {
|
if args.check {
|
||||||
let mut file = open_file(&path)?;
|
for path in process_rsp(&args.files)? {
|
||||||
if args.check {
|
let file = open_file(&path)?;
|
||||||
check(&args, &mut BufReader::new(file))?
|
check(&args, &mut BufReader::new(file))?;
|
||||||
} else {
|
}
|
||||||
hash(&mut file, &path)?
|
if let Some(out_path) = &args.output {
|
||||||
|
touch(out_path)
|
||||||
|
.with_context(|| format!("Failed to touch output file '{}'", out_path.display()))?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut w: Box<dyn Write> =
|
||||||
|
if let Some(out_path) = &args.output {
|
||||||
|
Box::new(buf_writer(out_path).with_context(|| {
|
||||||
|
format!("Failed to open output file '{}'", out_path.display())
|
||||||
|
})?)
|
||||||
|
} else {
|
||||||
|
Box::new(stdout())
|
||||||
|
};
|
||||||
|
for path in process_rsp(&args.files)? {
|
||||||
|
let mut file = open_file(&path)?;
|
||||||
|
hash(w.as_mut(), &mut file, &path)?
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if let Some(out_path) = args.output {
|
|
||||||
touch(&out_path)
|
|
||||||
.with_context(|| format!("Failed to touch output file '{}'", out_path.display()))?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -98,13 +111,16 @@ where R: BufRead + ?Sized {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash<R>(reader: &mut R, path: &Path) -> Result<()>
|
fn hash<R, W>(w: &mut W, reader: &mut R, path: &Path) -> Result<()>
|
||||||
where R: Read + ?Sized {
|
where
|
||||||
|
R: Read + ?Sized,
|
||||||
|
W: Write + ?Sized,
|
||||||
|
{
|
||||||
let hash = file_sha1(reader)?;
|
let hash = file_sha1(reader)?;
|
||||||
let mut hash_buf = [0u8; 40];
|
let mut hash_buf = [0u8; 40];
|
||||||
let hash_str = base16ct::lower::encode_str(&hash, &mut hash_buf)
|
let hash_str = base16ct::lower::encode_str(&hash, &mut hash_buf)
|
||||||
.map_err(|e| anyhow!("Failed to encode hash: {e}"))?;
|
.map_err(|e| anyhow!("Failed to encode hash: {e}"))?;
|
||||||
println!("{} {}", hash_str, path.display());
|
writeln!(w, "{} {}", hash_str, path.to_slash_lossy())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue