nestrs-cli-rs 0.1.0

Rust port of the Nest CLI for the nestrs organization.
Documentation
//! File readers for upstream `lib/readers`.

pub mod file_system_reader;
pub mod reader;

use std::fs;
use std::io;
use std::path::PathBuf;

use crate::error::{CliError, Result};

#[derive(Debug)]
pub struct ReaderFileLackPermissionsError(pub io::Error);

pub trait Reader {
    fn read(&self, name: &str) -> Result<String>;
}

#[derive(Clone, Debug)]
pub struct FileSystemReader {
    directory: PathBuf,
}

impl FileSystemReader {
    pub fn new(directory: impl Into<PathBuf>) -> Self {
        Self {
            directory: directory.into(),
        }
    }

    pub fn read_any_of(&self, filenames: &[&str]) -> Result<Option<String>> {
        let mut first_permission_error = None;

        for filename in filenames {
            match self.read(filename) {
                Ok(content) => return Ok(Some(content)),
                Err(CliError::Io(error)) if error.kind() == io::ErrorKind::NotFound => {}
                Err(CliError::Io(error)) if is_permission_error(&error) => {
                    first_permission_error.get_or_insert(error);
                }
                Err(error) => return Err(error),
            }
        }

        if let Some(error) = first_permission_error {
            Err(CliError::Io(error))
        } else {
            Ok(None)
        }
    }

    pub fn directory(&self) -> &std::path::Path {
        &self.directory
    }
}

impl Reader for FileSystemReader {
    fn read(&self, name: &str) -> Result<String> {
        fs::read_to_string(self.directory.join(name)).map_err(CliError::from)
    }
}

fn is_permission_error(error: &io::Error) -> bool {
    matches!(
        error.kind(),
        io::ErrorKind::PermissionDenied | io::ErrorKind::ReadOnlyFilesystem
    )
}