1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
use crate::file::File; use anyhow::{self, format_err, Context, Error}; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use std::path::{Path, PathBuf}; #[derive(Debug, Clone, PartialEq)] pub(crate) struct Dir { root_rel_path: PathBuf, abs_path: PathBuf, files: Vec<File>, dirs: Vec<Dir>, } impl Dir { pub fn from_disk<Q: AsRef<Path>, P: Into<PathBuf>>(root: Q, path: P) -> Result<Dir, Error> { let abs_path = path.into(); let root = root.as_ref(); let root_rel_path = abs_path.strip_prefix(&root).unwrap().to_path_buf(); if !abs_path.exists() { return Err(format_err!("The directory doesn't exist")); } let mut files = Vec::new(); let mut dirs = Vec::new(); for entry in abs_path.read_dir().context("Couldn't read the directory")? { let entry = entry?.path(); if entry.is_file() { files.push(File::from_disk(&root, entry)?); } else if entry.is_dir() { dirs.push(Dir::from_disk(&root, entry)?); } } Ok(Dir { root_rel_path, abs_path, files, dirs, }) } } impl ToTokens for Dir { fn to_tokens(&self, tokens: &mut TokenStream) { let root_rel_path = self.root_rel_path.display().to_string(); let files = &self.files; let dirs = &self.dirs; let tok = quote! { $crate::Dir { path: #root_rel_path, files: &[#( #files ),*], dirs: &[#( #dirs ),*], } }; tok.to_tokens(tokens); } }