use std::process::Command;
use super::*;
pub fn parse_files<P: AsRef<Path>>(rootdir: P, pattern: &str, mut files: Vec<PathBuf>)
-> Result<Vec<(PathBuf, PathBuf)>, Error> {
let rootdir = rootdir.as_ref();
let mut os_files = vec![];
for file in files.drain(..) {
let can_file = rootdir.join(file).canonicalize()?; let can_file = can_file.into_os_string();
trace!("Working on links from {:?}", can_file);
os_files.push(can_file);
}
if os_files.is_empty() {
return Ok(vec![]);
}
let rootdir = &rootdir.canonicalize()?;
let output = Command::new("rg") .arg("--no-heading")
.arg("-N")
.arg("-o")
.arg("--with-filename")
.arg(pattern)
.args(os_files)
.output()?; let output = String::from_utf8_lossy(&output.stdout);
process_output(&rootdir, output) }
fn process_output<P: AsRef<Path>, T: AsRef<str>>(rootdir: P, output: T)
-> Result<Vec<(PathBuf, PathBuf)>, Error> {
let rootdir = rootdir.as_ref();
let output = output.as_ref();
let mut collected_links: Vec<(PathBuf, PathBuf)> = vec![];
for line in output.lines() {
let v: Vec<&str> = line.splitn(2, ":").collect();
let f = v[0]; let v: Vec<&str> = v[1].splitn(2, "](").collect();
let temp_v = v[1].split(')');
let mut i = 0;
for part in temp_v {
i += part.len();
if part.contains('(') {
i += 1; } else {
break;
}
}
let (target, _) = v[1].split_at(i);
if !target.starts_with("http") {
let target = normalize_link(rootdir, Path::new(f), Path::new(target))?; let f = normalize_path(Path::new(rootdir), Path::new(f))?; collected_links.push((f, target));
}
}
Ok(collected_links)
}
#[cfg(test)]
mod tests {
extern crate tempfile;
use self::tempfile::tempdir;
use super::*;
use examples::*;
#[test]
fn test_process_ripgrep_output() {
let tmp_dir = tempdir().expect("Failed to setup temp dir");
let dir = tmp_dir.path();
generate_bare_examples(dir).expect("Failed to generate examples");
let rootdir = dir.join("examples/Zettelkasten/");
let c_root = rootdir.canonicalize()
.expect("Failed to resolve the example directory for this test.");
let mut output = c_root.join("subdir/file4.md").into_os_string().into_string()
.expect("Something went wrong.");
output.push_str(":[File 1 in the root directory](../file1.md)\n");
output.push_str(c_root.join("subdir/file5.md").as_os_str().to_str().unwrap());
output.push_str(":[block](../file1.md)\n");
output.push_str(c_root.join("file2.md").as_os_str().to_str().unwrap());
output.push_str(":[one more hyperlink](http://example.com)\n");
output.push_str(c_root.join("file2.md").as_os_str().to_str().unwrap());
output.push_str(":[hair](file3.md)\n");
let collected_links = process_output(&rootdir, output);
trace!("{:?}", collected_links);
assert!(collected_links.is_ok());
let collected_links = collected_links.unwrap();
assert_eq!(collected_links.len(), 3);
assert!(collected_links.contains(
&(PathBuf::from("subdir/file4.md"), PathBuf::from("file1.md"))
));
assert!(collected_links.contains(
&(PathBuf::from("subdir/file5.md"), PathBuf::from("file1.md"))
));
assert!(collected_links.contains(
&(PathBuf::from("file2.md"), PathBuf::from("file3.md"))
));
}
#[test]
fn test_ripgrep_files() {
let tmp_dir = tempdir().expect("Failed to setup temp dir");
let dir = tmp_dir.path();
generate_bare_examples(dir).expect("Failed to generate examples");
let rootdir = dir.join("examples/Zettelkasten/");
let files = vec![PathBuf::from("subdir/file4.md"),
PathBuf::from("subdir/file5.md"),
PathBuf::from("file2.md")];
let output = parse_files(&rootdir, PATTERN, files);
assert!(output.is_ok());
let output = output.unwrap();
assert_eq!(output.len(), 3);
assert!(output.contains(
&(PathBuf::from("subdir/file4.md"), PathBuf::from("file1.md"))
));
assert!(output.contains(
&(PathBuf::from("subdir/file5.md"), PathBuf::from("file1.md"))
));
assert!(output.contains(
&(PathBuf::from("file2.md"), PathBuf::from("file3.md"))
));
}
#[test]
fn test_process_ripgrep_output_bad_link() {
let tmp_dir = tempdir().expect("Failed to setup temp dir");
let dir = tmp_dir.path();
generate_bare_examples(dir).expect("Failed to generate examples");
let rootdir = dir.join("examples/Zettelkasten/");
let c_root = rootdir.canonicalize()
.expect("Failed to resolve the example directory for this test.");
let mut output = c_root.join("subdir/file4.md").into_os_string().into_string()
.expect("Something went wrong.");
output.push_str(":[File 1 in the root directory](../file1.md)\n");
output.push_str(c_root.join("subdir/file5.md").as_os_str().to_str().unwrap());
output.push_str(":[block](../file1.md)\n");
output.push_str(c_root.join("file2.md").as_os_str().to_str().unwrap());
output.push_str(":[one more hyperlink](http://example.com)\n");
output.push_str(c_root.join("file2.md").as_os_str().to_str().unwrap());
output.push_str(":[hair](foo.md)\n");
let collected_links = process_output(&rootdir, output);
trace!("{:?}", collected_links);
assert!(collected_links.is_err());
let e = collected_links.unwrap_err();
match e {
Error::BadLink(source, wrong_link, inner) => {
assert_eq!(source, c_root.join("file2.md"));
assert!(wrong_link.ends_with("foo.md"));
assert_eq!(inner.kind(), std::io::ErrorKind::NotFound);
assert!(inner.to_string().contains("No such file or directory"));
},
_ => panic!("Expected BadLink error, found {:#?}", e),
}
}
}