Skip to content

Commit

Permalink
Add remove_markers
Browse files Browse the repository at this point in the history
  • Loading branch information
tsoutsman committed Aug 26, 2021
1 parent e0a9ed4 commit 4c2e2f5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub enum Error {
FileSystem(ignore::Error),
IoError(std::io::Error),
NoMatch,
ExpectedMarker,
}

impl std::fmt::Display for Error {
Expand All @@ -13,6 +14,7 @@ impl std::fmt::Display for Error {
Error::FileSystem(_) => "file system error",
Error::IoError(_) => "io error",
Error::NoMatch => "no matches found in the given input",
Error::ExpectedMarker => "expected a marker but reached eof",
};

write!(f, "{}", result)
Expand Down
59 changes: 47 additions & 12 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::error::{Error, Result};

use std::{
convert::TryFrom,
io::{BufRead, BufReader, Write},
path::{Path, PathBuf},
};

Expand All @@ -13,13 +14,17 @@ use grep::{
use ignore::WalkBuilder;

lazy_static::lazy_static! {
pub static ref MATCHER: RegexMatcher = RegexMatcher::new_line_matcher(r"\{\{(?P<start>#|/)\s*lurien\s+(?P<hostname>[A-Za-z0-9\-_]+)\s*\}\}").unwrap();
pub static ref MATCHER: RegexMatcher = RegexMatcher::new_line_matcher(
r"\{\{(?P<start>#|/)\s*lurien\s+(?P<hostname>[A-Za-z0-9\-_]+)\s*\}\}",
)
// Unwrap is safe as this regex is tested.
.unwrap();
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Marker {
/// If the [`Marker`] is an opening marker (i.e. `{{#`) then this is true. Otherwise (i.e.
/// closing marker / `{{/`) it's set to false.
/// closing marker i.e. `{{/`) it's set to false.
pub is_opening: bool,
/// The line number of the marker when all the other markers are in the file.
pub lnum: u64,
Expand Down Expand Up @@ -73,12 +78,12 @@ impl std::convert::TryFrom<&str> for Marker {
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct File {
pub struct MarkedFile {
pub path: PathBuf,
pub markers: Vec<Marker>,
}

impl std::convert::From<PathBuf> for File {
impl std::convert::From<PathBuf> for MarkedFile {
fn from(path: PathBuf) -> Self {
Self {
path,
Expand All @@ -87,7 +92,9 @@ impl std::convert::From<PathBuf> for File {
}
}

pub fn walk_dir<P: AsRef<Path>>(path: P) -> Result<Vec<File>> {
/// Get all files containing markers, and the position of those markers, in a given directory.
/// The function will search the directory recursively.
pub fn markers<P: AsRef<Path>>(path: P) -> Result<Vec<MarkedFile>> {
// `.hidden(false)` means **include** hidden files.
let walker = WalkBuilder::new(path).hidden(false).build();

Expand All @@ -97,14 +104,15 @@ pub fn walk_dir<P: AsRef<Path>>(path: P) -> Result<Vec<File>> {

for entry in walker {
let entry = entry?;
let mut file = File::from(entry.into_path());
let mut file = MarkedFile::from(entry.into_path());

// TODO this will not be necessary in Rust 2021 when closures can partially move structs.
let path = file.path.clone();

searcher.search_path(
&*MATCHER,
path,
// TODO this sink or lossy?
grep::searcher::sinks::UTF8(|lnum, line| {
// Unwrap is safe as the line is guaranteed to contain a match.
file.markers
Expand All @@ -119,6 +127,37 @@ pub fn walk_dir<P: AsRef<Path>>(path: P) -> Result<Vec<File>> {
Ok(file_matches)
}

pub fn remove_markers(files: Vec<MarkedFile>) -> Result<()> {
for marked_file in files {
let mut result = String::new();
let mut file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(marked_file.path)?;

let mut lines = BufReader::new(&file).lines().enumerate();
let mut lnum = 0;

for marker in marked_file.markers {
while lnum < marker.lnum {
let next = match lines.next() {
Some((lnum, line)) => (lnum, line?),
None => return Err(Error::ExpectedMarker),
};

lnum = next.0 as u64;
let line_content = next.1;

result.push_str(&line_content);
}
}

file.write_all(result.as_bytes())?;
}

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -127,11 +166,7 @@ mod tests {
let mut result = String::new();

result += "{{";
if is_opening {
result += "#";
} else {
result += "/"
}
result += if is_opening { "#" } else { "/" };
result += whitespace;
result += "lurien";
result += " ";
Expand Down Expand Up @@ -172,7 +207,7 @@ mod tests {
#[test]
fn test_into_marker_err() {
let tests = vec![
"{#lurien singlequotes}",
"{#lurien singlebraces}",
"{{ #lurien thing}}",
// ^ illegal
"{{#lurien name with space}}",
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
)]

pub mod app;
// Ignore the error module in code coverage.
#[cfg(not(tarpaulin_include))]
pub mod error;
pub mod fs;
pub mod populate;
Expand Down

0 comments on commit 4c2e2f5

Please sign in to comment.