anesis 0.9.1

CLI for scaffolding projects from remote templates and extending them with project addons
Documentation
use std::path::Path;

use anyhow::{Result, anyhow};
use inquire::Select;

use crate::addons::manifest::{IfNotFound, InjectStep};

use super::{Rollback, render_lines, resolve_target};

pub fn execute_inject(
  step: &InjectStep,
  project_root: &Path,
  ctx: &tera::Context,
) -> Result<Vec<Rollback>> {
  let paths = resolve_target(&step.target, project_root)?;
  let lines: Vec<String> = step.content.lines().map(str::to_string).collect();
  let rendered = render_lines(&lines, ctx)?;

  let mut rollbacks = Vec::new();

  for path in paths {
    let original = std::fs::read(&path)?;
    let mut file_lines: Vec<String> = String::from_utf8_lossy(&original)
      .lines()
      .map(str::to_string)
      .collect();

    let marker = step.after.as_deref().or(step.before.as_deref());

    if let Some(marker) = marker {
      match file_lines.iter().position(|l| l.contains(marker)) {
        Some(idx) => {
          let insert_idx = if step.after.is_some() { idx + 1 } else { idx };
          for (i, line) in rendered.iter().enumerate() {
            file_lines.insert(insert_idx + i, line.clone());
          }
        }
        None => match step.if_not_found {
          IfNotFound::Skip => continue,
          IfNotFound::Error => {
            return Err(anyhow!(
              "Marker {:?} not found in {}",
              marker,
              path.display()
            ));
          }
          IfNotFound::WarnAndAsk => {
            eprintln!(
              "Warning: marker {:?} not found in {}",
              marker,
              path.display()
            );
            let choice =
              Select::new("How would you like to proceed?", vec!["Continue", "Abort"]).prompt()?;
            if choice == "Abort" {
              return Err(anyhow!("Aborted by user"));
            }
            continue;
          }
        },
      }
    } else {
      let mut new_lines = rendered.clone();
      new_lines.extend(file_lines);
      file_lines = new_lines;
    }

    rollbacks.push(Rollback::RestoreFile {
      path: path.clone(),
      original,
    });
    std::fs::write(&path, file_lines.join("\n"))?;
  }

  Ok(rollbacks)
}