1use std::fs;
2
3use anyhow::{Context, Result};
4use async_trait::async_trait;
5use spin_common::ui::quoted_path;
6use toml_edit::DocumentMut;
7
8use crate::Treatment;
9
10pub mod trigger;
12pub mod upgrade;
14pub mod version;
16
17#[async_trait]
19pub trait ManifestTreatment {
20 fn summary(&self) -> String;
23
24 async fn treat_manifest(&self, doc: &mut DocumentMut) -> Result<()>;
26}
27
28#[async_trait]
29impl<T: ManifestTreatment + Sync> Treatment for T {
30 fn summary(&self) -> String {
31 ManifestTreatment::summary(self)
32 }
33
34 async fn dry_run(&self, patient: &crate::PatientApp) -> Result<String> {
35 let mut after_doc = patient.manifest_doc.clone();
36 self.treat_manifest(&mut after_doc).await?;
37 let before = patient.manifest_doc.to_string();
38 let after = after_doc.to_string();
39 let diff = similar::udiff::unified_diff(Default::default(), &before, &after, 1, None);
40 Ok(format!(
41 "Apply the following diff to {}:\n{}",
42 quoted_path(&patient.manifest_path),
43 diff
44 ))
45 }
46
47 async fn treat(&self, patient: &mut crate::PatientApp) -> Result<()> {
48 let doc = &mut patient.manifest_doc;
49 self.treat_manifest(doc).await?;
50 let path = &patient.manifest_path;
51 fs::write(path, doc.to_string())
52 .with_context(|| format!("failed to write fixed manifest to {}", quoted_path(path)))
53 }
54}