Skip to main content

oxide_cli/addons/steps/
inject.rs

1use std::path::Path;
2
3use anyhow::{anyhow, Result};
4use inquire::Select;
5
6use crate::addons::manifest::{IfNotFound, InjectStep};
7
8use super::{Rollback, render_lines, resolve_target};
9
10pub fn execute_inject(
11  step: &InjectStep,
12  project_root: &Path,
13  ctx: &tera::Context,
14) -> Result<Vec<Rollback>> {
15  let paths = resolve_target(&step.target, project_root)?;
16  let lines: Vec<String> = step.content.lines().map(str::to_string).collect();
17  let rendered = render_lines(&lines, ctx)?;
18
19  let mut rollbacks = Vec::new();
20
21  for path in paths {
22    let original = std::fs::read(&path)?;
23    let mut file_lines: Vec<String> =
24      String::from_utf8_lossy(&original).lines().map(str::to_string).collect();
25
26    let marker = step.after.as_deref().or(step.before.as_deref());
27
28    if let Some(marker) = marker {
29      match file_lines.iter().position(|l| l.contains(marker)) {
30        Some(idx) => {
31          let insert_idx = if step.after.is_some() { idx + 1 } else { idx };
32          for (i, line) in rendered.iter().enumerate() {
33            file_lines.insert(insert_idx + i, line.clone());
34          }
35        }
36        None => match step.if_not_found {
37          IfNotFound::Skip => continue,
38          IfNotFound::Error => {
39            return Err(anyhow!("Marker {:?} not found in {}", marker, path.display()));
40          }
41          IfNotFound::WarnAndAsk => {
42            eprintln!("Warning: marker {:?} not found in {}", marker, path.display());
43            let choice =
44              Select::new("How would you like to proceed?", vec!["Continue", "Abort"]).prompt()?;
45            if choice == "Abort" {
46              return Err(anyhow!("Aborted by user"));
47            }
48            continue;
49          }
50        },
51      }
52    } else {
53      let mut new_lines = rendered.clone();
54      new_lines.extend(file_lines);
55      file_lines = new_lines;
56    }
57
58    rollbacks.push(Rollback::RestoreFile { path: path.clone(), original });
59    std::fs::write(&path, file_lines.join("\n"))?;
60  }
61
62  Ok(rollbacks)
63}