cfn-guard 3.2.0

AWS CloudFormation Guard is an open-source general-purpose policy-as-code evaluation tool. It provides developers with a simple-to-use, yet powerful and expressive domain-specific language (DSL) to define policies and enables developers to validate JSON- or YAML- formatted structured data with those policies.
Documentation
use std::cmp::{self, Ordering};
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::PathBuf;

use crate::rules::errors::Error;
use walkdir::WalkDir;

pub(crate) fn read_file_content(file: File) -> crate::rules::Result<String> {
    let mut file_content = String::new();
    let mut buf_reader = BufReader::new(file);
    buf_reader.read_to_string(&mut file_content)?;
    Ok(file_content)
}

pub(crate) fn get_files_with_filter<S, F>(
    file: &str,
    sort: S,
    filter: F,
) -> Result<Vec<PathBuf>, Error>
where
    S: FnMut(&walkdir::DirEntry, &walkdir::DirEntry) -> Ordering + Send + Sync + 'static,
    F: Fn(&walkdir::DirEntry) -> bool,
{
    let walker = WalkDir::new(file).sort_by(sort).into_iter();

    let selected = walker
        .filter_entry(|entry| entry.path().is_dir() || filter(entry))
        .flatten()
        .filter(|entry| entry.path().is_file())
        .map(|entry| entry.into_path())
        .collect::<Vec<_>>();

    Ok(selected)
}

#[derive(Debug)]
pub(crate) struct Iter<'i, T, C>
where
    C: Fn(String, &PathBuf) -> Result<T, Error>,
{
    files: &'i [PathBuf],
    index: usize,
    converter: C,
}

impl<'i, T, C> Iterator for Iter<'i, T, C>
where
    C: Fn(String, &PathBuf) -> Result<T, Error>,
{
    type Item = Result<T, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.files.len() {
            return None;
        }
        let next = &self.files[self.index];
        self.index += 1;
        let file = match File::open(next) {
            Ok(file) => file,
            Err(e) => return Some(Err(Error::from(e))),
        };
        let content = match read_file_content(file) {
            Ok(content) => content,
            Err(e) => return Some(Err(e)),
        };
        Some((self.converter)(content, next))
    }
}

pub(crate) fn iterate_over<T, C>(files: &[PathBuf], converter: C) -> Iter<T, C>
where
    C: Fn(String, &PathBuf) -> Result<T, Error>,
{
    Iter {
        files,
        converter,
        index: 0,
    }
}

pub(crate) fn alphabetical(first: &walkdir::DirEntry, second: &walkdir::DirEntry) -> Ordering {
    first.file_name().cmp(second.file_name())
}

pub(crate) fn last_modified(first: &walkdir::DirEntry, second: &walkdir::DirEntry) -> Ordering {
    if let Ok(first) = first.metadata() {
        if let Ok(second) = second.metadata() {
            if let Ok(first) = first.modified() {
                if let Ok(second) = second.modified() {
                    return first.cmp(&second);
                }
            }
        }
    }

    Ordering::Equal
}

pub(crate) fn regular_ordering(
    _first: &walkdir::DirEntry,
    _second: &walkdir::DirEntry,
) -> Ordering {
    Ordering::Equal
}

pub(crate) fn walk_dir(
    base: PathBuf,
    cmp: fn(&walkdir::DirEntry, &walkdir::DirEntry) -> cmp::Ordering,
) -> std::iter::Flatten<walkdir::IntoIter> {
    walkdir::WalkDir::new(base)
        .sort_by(cmp)
        .into_iter()
        .flatten()
}