use eyre::Result;
use std::path::Path;
use std::path::PathBuf;
use tokio::fs;
pub async fn discover_terraform_source_dirs<P: AsRef<Path>>(dir_path: P) -> Result<Vec<PathBuf>> {
let dir_path = dir_path.as_ref();
let mut terraform_dirs = Vec::new();
let mut dirs_to_process = vec![dir_path.to_path_buf()];
while let Some(current_dir) = dirs_to_process.pop() {
let mut entries = match fs::read_dir(¤t_dir).await {
Ok(entries) => entries,
Err(_) => continue, };
let mut has_tf_files = false;
while let Some(entry) = entries.next_entry().await? {
let path = entry.path();
let metadata = entry.metadata().await?;
if metadata.is_file() {
if let Some(extension) = path.extension()
&& extension == "tf"
{
has_tf_files = true;
}
} else if metadata.is_dir() {
dirs_to_process.push(path);
}
}
if has_tf_files {
terraform_dirs.push(current_dir);
}
}
Ok(terraform_dirs)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
use tokio::fs;
#[tokio::test]
async fn test_discover_terraform_source_dirs() -> Result<()> {
let temp_dir = TempDir::new()?;
let temp_path = temp_dir.path();
fs::write(temp_path.join("main.tf"), "# Main terraform file").await?;
let subdir1 = temp_path.join("subdir1");
fs::create_dir(&subdir1).await?;
fs::write(subdir1.join("resource.tf"), "# Resource terraform file").await?;
let nested = subdir1.join("nested");
fs::create_dir(&nested).await?;
fs::write(nested.join("provider.tf"), "# Provider terraform file").await?;
let subdir2 = temp_path.join("subdir2");
fs::create_dir(&subdir2).await?;
fs::write(subdir2.join("README.md"), "# No terraform files here").await?;
let result = discover_terraform_source_dirs(temp_path).await?;
assert_eq!(result.len(), 3);
assert!(result.contains(&temp_path.to_path_buf()));
assert!(result.contains(&subdir1));
assert!(result.contains(&nested));
assert!(!result.contains(&subdir2));
Ok(())
}
#[tokio::test]
async fn test_empty_directory() -> Result<()> {
let temp_dir = TempDir::new()?;
let temp_path = temp_dir.path();
let result = discover_terraform_source_dirs(temp_path).await?;
assert!(result.is_empty());
Ok(())
}
#[tokio::test]
async fn test_directory_with_only_subdirs_no_tf() -> Result<()> {
let temp_dir = TempDir::new()?;
let temp_path = temp_dir.path();
let subdir = temp_path.join("subdir");
fs::create_dir(&subdir).await?;
fs::write(subdir.join("config.json"), "{}").await?;
let result = discover_terraform_source_dirs(temp_path).await?;
assert!(result.is_empty());
Ok(())
}
}