use std::path::{Path, PathBuf};
use xacli::testing::spec::{SpecFile, TapeFile};
use xacli::Context;
pub fn build_command(ctx: &mut dyn Context) -> xacli::Result<()> {
let info = ctx.info();
let input_value = info
.args
.get("directory")
.ok_or_else(|| xacli::Error::custom("Missing directory argument"))?;
let directory: String = input_value
.clone()
.try_into()
.map_err(|e| xacli::Error::custom(format!("Failed to parse directory: {}", e)))?;
let dir_path = Path::new(&directory);
if !dir_path.exists() {
return Err(xacli::Error::custom(format!(
"Directory does not exist: {}",
directory
)));
}
if !dir_path.is_dir() {
return Err(xacli::Error::custom(format!(
"Path is not a directory: {}",
directory
)));
}
let xacli_dir = Path::new(".xacli");
let tapes_dir = xacli_dir.join("tapes");
std::fs::create_dir_all(&tapes_dir)
.map_err(|e| xacli::Error::custom(format!("Failed to create tapes directory: {}", e)))?;
let gitignore_path = xacli_dir.join(".gitignore");
if !gitignore_path.exists() {
std::fs::write(&gitignore_path, "gifs/\nreports/\n")
.map_err(|e| xacli::Error::custom(format!("Failed to create .gitignore: {}", e)))?;
}
let pattern = format!("{}/**/*.xacli.hcl", directory);
let paths: Vec<PathBuf> = glob::glob(&pattern)
.map_err(|e| xacli::Error::custom(format!("Failed to read glob pattern: {}", e)))?
.filter_map(Result::ok)
.collect();
if paths.is_empty() {
println!("No .xacli.hcl files found in {}", directory);
return Ok(());
}
let mut converted = 0;
let total = paths.len();
for hcl_path in paths {
match convert_to_tape(&hcl_path, &tapes_dir) {
Ok(tape_path) => {
converted += 1;
use owo_colors::OwoColorize;
println!("{} Generated: {}", "✓".green().bold(), tape_path.display());
}
Err(e) => {
use owo_colors::OwoColorize;
eprintln!(
"{} Error processing {}: {}",
"✗".red().bold(),
hcl_path.display(),
e
);
}
}
}
println!("\nProcessed {}/{} files successfully", converted, total);
Ok(())
}
fn convert_to_tape(
hcl_path: &Path,
tapes_dir: &Path,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
let spec = SpecFile::parse_file(hcl_path)?;
let base_name = hcl_path
.file_stem()
.and_then(|s| s.to_str())
.ok_or("Invalid filename")?
.trim_end_matches(".xacli");
let cli_config = spec
.cli
.as_ref()
.ok_or("CLI config is required in .xacli.hcl file")?;
let tape = if !spec.example.is_empty() {
TapeFile::from((cli_config, &spec.example))
} else {
TapeFile::from((cli_config.path.as_str(), &spec))
};
let tape_path = tapes_dir.join(format!("{}.tape", base_name));
tape.save(&tape_path)?;
Ok(tape_path)
}