You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ripgrep-all/src/preproc.rs

173 lines
6.4 KiB
Rust

5 years ago
use crate::adapters::*;
use crate::args::RgaArgs;
5 years ago
use crate::matching::*;
5 years ago
use crate::CachingWriter;
use failure::*;
use log::*;
5 years ago
use path_clean::PathClean;
use std::convert::TryInto;
use std::io::BufRead;
use std::io::BufReader;
5 years ago
use std::io::BufWriter;
use std::sync::{Arc, RwLock};
5 years ago
#[derive(Clone)]
pub struct PreprocConfig<'a> {
pub cache: Option<Arc<RwLock<dyn crate::preproc_cache::PreprocCache>>>,
pub args: &'a RgaArgs,
5 years ago
}
5 years ago
/**
* preprocess a file as defined in `ai`.
*
* If a cache is passed, read/write to it.
*
*/
pub fn rga_preproc(ai: AdaptInfo) -> Fallible<()> {
5 years ago
let AdaptInfo {
filepath_hint,
5 years ago
is_real_file,
5 years ago
inp,
oup,
line_prefix,
config,
archive_recursion_depth,
5 years ago
..
} = ai;
let PreprocConfig { mut cache, args } = config;
let adapters = adapter_matcher(&args.adapters[..], args.accurate)?;
5 years ago
let filename = filepath_hint
.file_name()
5 years ago
.ok_or_else(|| format_err!("Empty filename"))?;
debug!("depth: {}", archive_recursion_depth);
if archive_recursion_depth >= args.max_archive_recursion {
writeln!(oup, "{}[rga: max archive recursion reached]", line_prefix)?;
return Ok(());
}
5 years ago
debug!("path_hint: {:?}", filepath_hint);
5 years ago
// todo: figure out when using a bufreader is a good idea and when it is not
// seems to be good for File::open() reads, but not sure about within archives (tar, zip)
let inp = &mut BufReader::with_capacity(1 << 13, inp);
let mimetype = if args.accurate {
let buf = inp.fill_buf()?; // fill but do not consume!
let mimetype = tree_magic::from_u8(buf);
debug!("mimetype: {:?}", mimetype);
Some(mimetype)
} else {
None
};
5 years ago
let adapter = adapters(FileMeta {
mimetype,
5 years ago
lossy_filename: filename.to_string_lossy().to_string(),
});
match adapter {
Some((adapter, detection_reason)) => {
let meta = adapter.metadata();
debug!(
"chose adapter '{}' because of matcher {:?}",
&meta.name, &detection_reason
);
5 years ago
eprintln!("adapter: {}", &meta.name);
let db_name = format!("{}.v{}", meta.name, meta.version);
if let Some(cache) = cache.as_mut() {
5 years ago
let cache_key: Vec<u8> = {
let clean_path = filepath_hint.to_owned().clean();
let meta = std::fs::metadata(&filepath_hint)?;
5 years ago
if adapter.metadata().recurses {
let key = (
clean_path,
meta.modified().expect("weird OS that can't into mtime"),
&args.adapters[..],
);
debug!("cache key: {:?}", key);
bincode::serialize(&key).expect("could not serialize path")
// key in the cache database
5 years ago
} else {
let key = (
clean_path,
meta.modified().expect("weird OS that can't into mtime"),
);
debug!("cache key: {:?}", key);
bincode::serialize(&key).expect("could not serialize path")
// key in the cache database
5 years ago
}
5 years ago
};
cache.write().unwrap().get_or_run(
&db_name,
&cache_key,
Box::new(|| -> Fallible<Option<Vec<u8>>> {
5 years ago
// wrapping BufWriter here gives ~10% perf boost
let mut compbuf = BufWriter::new(CachingWriter::new(
oup,
args.cache_max_blob_len.try_into().unwrap(),
args.cache_compression_level.try_into().unwrap(),
)?);
debug!("adapting...");
adapter.adapt(
AdaptInfo {
line_prefix,
filepath_hint,
is_real_file,
inp,
oup: &mut compbuf,
archive_recursion_depth,
config: PreprocConfig { cache: None, args },
},
&detection_reason,
)?;
5 years ago
let compressed = compbuf
.into_inner()
.map_err(|_| "could not finish zstd")
.unwrap()
.finish()?;
5 years ago
if let Some(cached) = compressed {
debug!("compressed len: {}", cached.len());
5 years ago
Ok(Some(cached))
} else {
Ok(None)
}
}),
Box::new(|cached| {
let stdouti = std::io::stdout();
zstd::stream::copy_decode(cached, stdouti.lock())?;
5 years ago
Ok(())
}),
)?;
Ok(())
5 years ago
} else {
debug!("adapting...");
adapter.adapt(
AdaptInfo {
line_prefix,
filepath_hint,
is_real_file,
inp,
oup,
archive_recursion_depth,
config: PreprocConfig { cache: None, args },
},
&detection_reason,
)?;
5 years ago
Ok(())
}
}
None => {
// allow passthrough if the file is in an archive or accurate matching is enabled
// otherwise it should have been filtered out by rg pre-glob since rg can handle those better than us
let allow_cat = !is_real_file || args.accurate;
5 years ago
if allow_cat {
spawning::postproc_line_prefix(line_prefix, inp, oup)?;
5 years ago
Ok(())
} else {
Err(format_err!(
"No adapter found for file {:?}, passthrough disabled.",
filename
))
5 years ago
}
}
}
}