use crate::types::{xvcpath::XvcPath, xvcroot::XvcRoot};
use crate::{XvcMetadata, XvcPathMetadataMap, CHANNEL_BOUND, XVCIGNORE_FILENAME};
use crate::error::{Error, Result};
use crossbeam_channel::{bounded, Sender};
use std::sync::{Arc, RwLock};
use std::thread;
use xvc_logging::{warn, XvcOutputSender};
use xvc_walker::{self, IgnoreRules, PathMetadata, WalkOptions};
use xvc_walker::{Result as XvcWalkerResult, SharedIgnoreRules};
pub const COMMON_IGNORE_PATTERNS: &str = ".xvc\n.git\n";
pub fn walk_serial(
output_snd: &XvcOutputSender,
xvc_root: &XvcRoot,
include_dirs: bool,
) -> Result<(XvcPathMetadataMap, IgnoreRules)> {
let walk_options = WalkOptions {
ignore_filename: Some(XVCIGNORE_FILENAME.to_owned()),
include_dirs,
};
let (res_paths, ignore_rules) = xvc_walker::walk_serial::walk_serial(
output_snd,
COMMON_IGNORE_PATTERNS,
xvc_root,
&walk_options,
)?;
let pmp: XvcPathMetadataMap = res_paths
.iter()
.filter_map(|pm| {
let md = XvcMetadata::from(&pm.metadata);
let rxp = XvcPath::new(xvc_root, xvc_root, &pm.path);
match rxp {
Ok(xvc_path) => Some((xvc_path, md)),
Err(e) => {
warn!(output_snd, "{:?}", e);
None
}
}
})
.collect();
Ok((pmp, ignore_rules))
}
pub fn walk_parallel(
xvc_root: &XvcRoot,
global_ignore_rules: &str,
include_dirs: bool,
) -> Result<(XvcPathMetadataMap, SharedIgnoreRules)> {
let (sender, receiver) = bounded::<(XvcPath, XvcMetadata)>(CHANNEL_BOUND);
let ignore_rules = Arc::new(RwLock::new(IgnoreRules::from_global_patterns(
xvc_root,
Some(XVCIGNORE_FILENAME),
global_ignore_rules,
)));
walk_channel(xvc_root, ignore_rules.clone(), include_dirs, sender)?;
let pmm = thread::spawn(move || {
let mut pmm = XvcPathMetadataMap::new();
for (path, md) in receiver.iter() {
pmm.insert(path, md);
}
pmm
})
.join()
.map_err(Error::from)?;
Ok((pmm, ignore_rules))
}
pub fn walk_channel(
xvc_root: &XvcRoot,
ignore_rules: SharedIgnoreRules,
include_dirs: bool,
xpm_upstream: Sender<(XvcPath, XvcMetadata)>,
) -> Result<()> {
let walk_options = WalkOptions {
ignore_filename: ignore_rules.read()?.ignore_filename.clone(),
include_dirs,
};
let (path_sender, path_receiver) = bounded::<XvcWalkerResult<PathMetadata>>(CHANNEL_BOUND);
xvc_walker::walk_parallel::walk_parallel(ignore_rules, xvc_root, walk_options, path_sender)?;
crossbeam::scope(|s| {
s.spawn(|_| {
for result in path_receiver {
match result {
Ok(pm) => {
let md: XvcMetadata = XvcMetadata::from(pm.metadata);
let rxp = XvcPath::new(xvc_root, xvc_root.absolute_path(), &pm.path);
match rxp {
Ok(xvc_path) => match xpm_upstream.send((xvc_path, md)) {
Ok(_) => {}
Err(err) => {
warn!("{:?}", err);
}
},
Err(e) => {
e.warn();
}
}
}
Err(e) => {
e.warn();
}
}
}
});
})
.map_err(Error::from)?;
Ok(())
}