/ manager / src / peeker.rs
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  }