peeker.rs
1 use crate::builder::TEMPLATE_EXTENSION; 2 use crate::error::{Error, ErrorLocation, Errors}; 3 use crate::Config; 4 use async_recursion::async_recursion; 5 use blueprint::parse_template; 6 use futures::future::join_all; 7 use std::ffi::OsStr; 8 use std::path::PathBuf; 9 use tokio::fs::{read_dir, read_to_string}; 10 use tokio::join; 11 12 pub async fn peek_tree(cfg: &Config) -> Result<(), Errors> { 13 for var in dir(cfg, PathBuf::new()).await? { 14 println!("{}", var); 15 } 16 17 Ok(()) 18 } 19 20 #[async_recursion] 21 async fn dir(cfg: &Config, relative: PathBuf) -> Result<Vec<String>, Errors> { 22 let template_path = cfg.template_dir.join(&relative); 23 24 info!("traversing {:?}", template_path); 25 26 let mut walker = read_dir(&template_path) 27 .await 28 .with_location(&template_path)?; 29 30 let mut dir_tasks = vec![]; 31 let mut file_tasks = vec![]; 32 33 while let Some(entry) = walker.next_entry().await.with_location(&template_path)? { 34 let meta = entry.metadata().await.with_location(&entry.path())?; 35 let new_relative = relative.join(entry.file_name()); 36 37 if meta.is_dir() { 38 dir_tasks.push(dir(cfg, new_relative)); 39 } else if meta.is_file() { 40 file_tasks.push(file(cfg, new_relative)); 41 } 42 } 43 44 let dirs = async { join_all(dir_tasks).await.into_iter().collect::<Vec<_>>() }; 45 let files = async { join_all(file_tasks).await.into_iter().collect::<Vec<_>>() }; 46 let (dirs, files) = join!(dirs, files); 47 48 let mut vars = vec![]; 49 let mut errors = vec![]; 50 51 for result in files.into_iter() { 52 match result { 53 Ok(mut more_vars) => vars.append(&mut more_vars), 54 Err(error) => errors.push(error), 55 } 56 } 57 58 let mut errors: Errors = errors.into(); 59 60 for result in dirs.into_iter() { 61 match result { 62 Ok(mut more_vars) => vars.append(&mut more_vars), 63 Err(error) => errors.join(error), 64 } 65 } 66 67 if errors.is_empty() { 68 vars.sort_unstable(); 69 vars.dedup(); 70 Ok(vars) 71 } else { 72 Err(errors) 73 } 74 } 75 76 async fn file(cfg: &Config, relative: PathBuf) -> Result<Vec<String>, Error> { 77 let template_path = cfg.template_dir.join(&relative); 78 79 if template_path.extension() != Some(OsStr::new(TEMPLATE_EXTENSION)) { 80 return Ok(vec![]); 81 } 82 83 debug!("reading {:?}", template_path); 84 85 // parse template 86 let file_str = read_to_string(&template_path) 87 .await 88 .with_location(&template_path)?; 89 90 let vars = parse_template(&file_str) 91 .with_location(&template_path)? 92 .list_variables() 93 .into_iter() 94 .map(|s| s.to_string()) 95 .collect(); 96 97 Ok(vars) 98 }