1use std::path::PathBuf;
4
5use anyhow::{bail, Context, Result};
6
7use crate::model::{Config, SplitPlan};
8use crate::plan::{child_path, render_child};
9
10pub struct Applied {
12 pub source_path: PathBuf,
13 parent_backup: String,
14 created_files: Vec<PathBuf>,
15 created_dir: Option<PathBuf>,
16 pub files: Vec<PathBuf>,
18}
19
20impl Applied {
21 pub fn rollback(&self) -> Result<()> {
24 std::fs::write(&self.source_path, &self.parent_backup)
25 .with_context(|| format!("rollback: restoring {}", self.source_path.display()))?;
26 for f in &self.created_files {
27 let _ = std::fs::remove_file(f);
28 }
29 if let Some(dir) = &self.created_dir {
30 let _ = std::fs::remove_dir(dir);
32 }
33 Ok(())
34 }
35}
36
37pub fn write_plan(plan: &SplitPlan, _config: &Config) -> Result<Applied> {
40 for file in &plan.files {
42 let path = child_path(plan, &file.stem);
43 if path.exists() {
44 bail!(
45 "target file {} already exists; refusing to overwrite",
46 path.display()
47 );
48 }
49 }
50
51 let parent_backup = std::fs::read_to_string(&plan.source_path)
52 .with_context(|| format!("reading {}", plan.source_path.display()))?;
53
54 let created_dir = if !plan.out_dir.exists() {
56 std::fs::create_dir_all(&plan.out_dir)
57 .with_context(|| format!("creating {}", plan.out_dir.display()))?;
58 Some(plan.out_dir.clone())
59 } else {
60 None
61 };
62
63 let mut created_files = Vec::new();
64 let mut all_files = Vec::new();
65 for file in &plan.files {
66 let path = child_path(plan, &file.stem);
67 let contents = render_child(plan, file);
68 std::fs::write(&path, contents)
69 .with_context(|| format!("writing {}", path.display()))?;
70 created_files.push(path.clone());
71 all_files.push(path);
72 }
73
74 std::fs::write(&plan.source_path, &plan.parent_contents)
75 .with_context(|| format!("writing {}", plan.source_path.display()))?;
76 all_files.push(plan.source_path.clone());
77
78 Ok(Applied {
79 source_path: plan.source_path.clone(),
80 parent_backup,
81 created_files,
82 created_dir,
83 files: all_files,
84 })
85}
86
87pub fn format_files(files: &[PathBuf], edition: &str) {
89 if files.is_empty() {
90 return;
91 }
92 let mut cmd = std::process::Command::new("rustfmt");
93 cmd.arg("--edition").arg(edition);
94 for f in files {
95 cmd.arg(f);
96 }
97 let _ = cmd.output();
98}